Skip to main content

⬡ Close Code × LLMesh

A terminal-native AI coding agent, and the universal LLM gateway behind it.

PyPI Python 3.10+ License: MIT Deploy to Render

pip install closecode

This repository holds two halves of one system:

What it is How you get it
⬡ Close Code A Textual TUI that lives in your terminal. Streaming chat, local session history, model switching. pip install closecode
🌐 LLMesh A stateless FastAPI gateway that fans requests out to OpenAI, Groq, NVIDIA NIM and OpenRouter behind one OpenAI-compatible API. Deploy to Render, Docker, or run locally

Close Code never talks to a provider directly. It holds one LLMesh key, and LLMesh holds the upstream keys — so provider credentials stay on the server and your prompts stay off disk anywhere but your own machine.

📘 Shipping it? DEPLOYMENT.md is the step-by-step guide for deploying the gateway to Render + Neon and publishing the client to PyPI, with a pre-flight checklist and troubleshooting table.


✨ Features

⬡ Close Code (terminal client)

  • 4:1 chat layout — a Textual interface with message bubbles, a welcome screen, and an info sidebar.
  • 100% local sessions — conversations are written to ~/.closecode/sessions/ as JSON. History never leaves your machine.
  • Model status probing — validates keys in the background and tags each model (● Key Valid, ⚠ Rate Limited, ✗ API Key Invalid).
  • Slash commands — /models, /session N, /rename, /new, and more.
  • Task extraction — parses your prompts into a live checklist in the sidebar.

🌐 LLMesh (gateway)

  • One API, many providers — OpenAI-compatible /v1/chat/completions, /v1/completions and /v1/embeddings routed to whichever upstream serves the requested model.
  • Stateless by design — prompts and responses are proxied, never persisted.
  • Postgres or SQLite — point it at Neon (or any managed Postgres) with one environment variable; falls back to a local SQLite file with zero configuration.
  • Usage accounting — per-key token quotas, batched writes, circuit breakers on failing upstreams.
  • Admin dashboard — manage upstream keys, models and quotas from the web UI.

🏗️ Architecture

Close Code owns the UI, context window and session storage. LLMesh owns routing, auth and accounting.

graph TD
    subgraph Local["Your machine"]
        O["⬡ Close Code TUI"]
        S[("~/.closecode/sessions/<br/>local JSON")]
        O <-->|reads / writes| S
    end

    subgraph Gateway["LLMesh gateway"]
        L["FastAPI server<br/>:8087 or Render"]
        DB[("Neon Postgres<br/>keys · models · usage")]
        L <-->|config + quotas| DB
    end

    subgraph Up["Upstream providers"]
        N["NVIDIA NIM"]
        G["Groq"]
        OR["OpenRouter"]
    end

    O -->|"POST /v1/chat/completions<br/>Authorization: Bearer &lt;LLMesh key&gt;"| L
    L -->|"+ upstream key"| N
    L -->|"+ upstream key"| G
    L -->|"+ upstream key"| OR

    N -->|SSE| L
    G -->|SSE| L
    OR -->|SSE| L
    L -->|SSE passthrough| O

Request lifecycle

  1. You type a prompt into Close Code.
  2. Close Code reads the local session file, assembles the message history, and estimates token usage.
  3. It POSTs an OpenAI-compatible payload to LLMesh.
  4. LLMesh looks up the model, checks your key's quota, attaches the upstream provider key, and forwards.
  5. Tokens stream back over SSE, straight through LLMesh to your terminal.
  6. On completion, Close Code saves the new state to ~/.closecode/sessions/, and LLMesh records token usage against your key.

🚀 Quick start

1. Install the client

pip install closecode

Prefer an isolated install? pipx install closecode works too.

2. Point it at a gateway

You need a running LLMesh instance and an API key from its dashboard. Either deploy your own or run one locally.

3. Launch

closecode

On first run you get an onboarding screen:

  1. Enter your LLMesh endpoint — http://localhost:8087 locally, or https://your-service.onrender.com if deployed.
  2. Paste your LLMesh API key.
  3. Hit Connect.

Close Code fetches the model list and drops you into the chat view. Settings are remembered in ~/.closecode/config.json.

Upgrading from the old ovo package? Your ~/.ovo directory is migrated to ~/.closecode automatically on first launch, sessions intact. You can pip uninstall ovo afterwards.


🌐 Deploying LLMesh to Render

The repo ships a render.yaml blueprint, so deployment is a form and two secrets. The condensed version is below; DEPLOYMENT.md has the fully expanded walkthrough.

Step 1 — Create a Neon Postgres database

  1. Sign up at neon.tech and create a project.

  2. Copy the connection string from the dashboard. It looks like:

    postgresql://neondb_owner:PASSWORD@ep-xxx-pooler.us-east-2.aws.neon.tech/neondb?sslmode=require
    

Nothing else to do — LLMesh creates its own tables on first boot.

Step 2 — Deploy the blueprint

  1. Push this repo to GitHub.

  2. In Render: New → Blueprint, and select the repo. Render reads render.yaml.

  3. Fill in the variables Render marks as required:

    Variable Value
    DATABASE_URL Your Neon connection string from step 1
    ADMIN_PASSWORD_HASH bcrypt hash of your admin password (below)
    OPENROUTER_API_KEY From openrouter.ai/keys
    GROQ_API_KEY From console.groq.com/keys
    NVIDIA_NIM_API_KEY From build.nvidia.com

    Generate the admin hash locally:

    python -c "import bcrypt; print(bcrypt.hashpw(b'your_password', bcrypt.gensalt()).decode())"
    
  4. Deploy. Render builds, runs the health check against /healthz, and gives you a URL.

SESSION_SECRET_KEY is generated by Render automatically. DOMAIN and API_BASE_URL are derived from Render's injected RENDER_EXTERNAL_URL, so CORS works on the generated hostname without configuration.

Step 3 — Seed models and mint a key

  1. Open https://your-service.onrender.com/dashboard and log in as admin.

  2. Add your upstream servers and models, or run the seed script against the same database:

    DATABASE_URL="postgresql://..." python -m scripts.seed_servers
    
  3. Register a user on the landing page to mint an LLMesh API key — that's what you paste into Close Code.

Free-plan note. Render's free web services sleep after inactivity, so the first request after an idle period takes a few seconds to wake. Neon's free compute suspends too; pool_pre_ping and a 300s connection recycle are already configured to handle both cleanly.


🖥️ Running LLMesh locally

git clone https://github.com/Dhanugupta0/LLMesh.git
cd LLMesh

python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

cp .env.example .env      # then fill in your provider keys
export DEV=1
./start.sh

The gateway comes up on http://localhost:8087. With no DATABASE_URL set it uses a local SQLite file at app/database/myapi.db — no Postgres needed for development.

With Docker

cp .env.example .env      # fill in your keys
docker compose up -d

Add --profile with-nginx to bring up the bundled Nginx reverse proxy.


⌨️ Command reference

Slash commands inside Close Code:

Command Description
/help Display the command reference
/models List models with provider and live status
/model <N> Switch to a model by index
/sessions List locally saved conversations
/session <N> Restore a previous conversation
/save Force-save the current session
/rename <T> Rename the current session
/new Start a fresh session
/clear Clear the display, keep the session
/exit Exit Close Code

🛠️ Configuration

Close Code (client)

Config lives at ~/.closecode/config.json, written by the onboarding screen. Environment variables override it:

Variable Description
CLOSECODE_API_URL LLMesh endpoint (also accepts LLMESH_API_URL)
CLOSECODE_API_KEY LLMesh API key (also accepts LLMESH_API_KEY)
Path Contents
~/.closecode/config.json Endpoint, key, model and UI preferences
~/.closecode/sessions/ Conversation history, one JSON file per session
~/.closecode/logs/ Client logs

LLMesh (gateway)

Full list with comments in .env.example. The ones that matter:

Variable Default Description
DATABASE_URL (unset) Postgres connection string. Unset ⇒ SQLite.
PGHOST / PGUSER / PGPASSWORD / PGDATABASE (unset) Neon's discrete variables — used when DATABASE_URL is unset
DATABASE_PATH app/database/myapi.db SQLite file location
SESSION_SECRET_KEY — Signing key for admin sessions. Required in production.
ADMIN_USERNAME admin Dashboard login
ADMIN_PASSWORD_HASH — bcrypt hash of the admin password
OPENROUTER_API_KEY — Upstream provider key
GROQ_API_KEY — Upstream provider key
NVIDIA_NIM_API_KEY — Upstream provider key
DEFAULT_LIMIT 1000000 Default per-key token quota
PORT 8087 Bind port (Render sets this automatically)
WEB_CONCURRENCY 4 Gunicorn worker count

Postgres notes. postgres:// and postgresql:// URLs are both accepted and rewritten onto asyncpg. libpq-only parameters (sslmode, channel_binding, ...) are stripped and translated into a real SSL context, so you can paste a Neon string verbatim. Prepared-statement caching is disabled so pooled endpoints (Neon's -pooler host, PgBouncer, Supavisor) work without extra configuration.


📡 API

LLMesh speaks the OpenAI wire format, so any OpenAI-compatible client works — not just Close Code.

curl https://your-service.onrender.com/v1/chat/completions \
  -H "Authorization: Bearer $LLMESH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "llama-3.3-70b-versatile",
    "messages": [{"role": "user", "content": "Hello"}],
    "stream": true
  }'
Endpoint Purpose
GET /healthz Liveness probe; 503 if the database is unreachable
GET /v1/models List available models
POST /v1/chat/completions Chat, streaming or buffered
POST /v1/completions Legacy completions
POST /v1/embeddings Embeddings
GET /dashboard Admin UI

📦 Releasing the client to PyPI

Publishing is automated by .github/workflows/publish.yml using PyPI Trusted Publishing, so no API token is stored anywhere. Full walkthrough in DEPLOYMENT.md.

One-time setup — on pypi.org/manage/account/publishing, add a pending publisher:

Field Value
PyPI project closecode
Owner Dhanugupta0
Repository LLMesh
Workflow publish.yml
Environment pypi

Each release:

# bump __version__ in closecode/__init__.py (the single source of truth —
# pyproject.toml reads it from there), commit, then:
git tag v0.1.0
git push origin v0.1.0

The workflow checks the tag matches the project version, builds an sdist and wheel, verifies theme.tcss is bundled, and uploads. To build locally:

pip install build twine
python -m build
twine check dist/*

🗂️ Repository layout

.
├── closecode/            # ⬡ the pip-installable terminal client
│   ├── app.py            #   Textual App, slash commands, streaming loop
│   ├── config.py         #   ~/.closecode config + legacy ~/.ovo migration
│   ├── sessions.py       #   local JSON session persistence
│   ├── llmesh/           #   HTTP client + SSE parsing
│   └── ui/               #   screens, widgets, theme.tcss
│
├── app/                  # 🌐 the LLMesh FastAPI gateway
│   ├── api/routes.py     #   OpenAI-compatible + dashboard routes
│   ├── core/             #   lifespan, middleware, background refresh
│   ├── database/         #   SQLAlchemy models, Postgres/SQLite engine
│   ├── services/         #   routing, usage queue, provider clients
│   └── config/settings.py#   environment configuration
│
├── static/ · templates/  # landing page + dashboard
├── scripts/              # database init and model seeding
├── DEPLOYMENT.md         # Render + PyPI step-by-step guide
├── render.yaml           # Render blueprint
├── Dockerfile · docker-compose.yml
└── pyproject.toml        # closecode packaging

📄 License

MIT — see LICENSE.

Built with 🖤 · closecode on PyPI

Metadata

Release files for closecode 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for closecode 0.1.0
File Size Uploaded
closecode-0.1.0.tar.gz 33.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for closecode 0.1.0
File Interpreter ABI Platform
closecode-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 68.0 kB

Release files / closecode-0.1.0.tar.gz

Download URL closecode-0.1.0.tar.gz
Size 33.8 kB
Tags Source
SHA-256 checksum
How to use checksums
40c60c8206ce954c11dc71b89dd89ffef68034010c194fb2c95f40c60d0a44af
BLAKE2b-256 checksum
How to use checksums
46991830e2762b210d1396e293875a929849ef78c5cccfcc6e592925967cd7e0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Release files / closecode-0.1.0-py3-none-any.whl

Download URL closecode-0.1.0-py3-none-any.whl
Size 34.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f5cae0222501887120b1895a5a5c493f380335482c1ec06479187471c65f8fab
BLAKE2b-256 checksum
How to use checksums
0035f92793e0677448b2d88d421773d33a74b92493f21bffe2d9078979eb56d0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page