Features Models Docs Pricing Open the workspace
Documentation

Everything, in one page.

Eltes is a static-first, local-first agent workspace. No build step or demo replies; an optional Vercel/local backend supports key checks and provider proxying. This guide covers keys, providers, CORS, the tool loop, accounts and where every byte actually lives.

v3.3.0 14 minute read No telemetry BYOK only

Overview

Eltes is a browser-based AI workspace. Connect a real provider account (or paste a key), pick a model, and Eltes streams that provider's answer, renders tool calls, and keeps history in this browser. Direct mode calls providers from the browser; an optional separately hosted Vercel/local proxy can test keys and forward requests. If a hosted provider is not connected, the app says so instead of inventing an answer — and Eltes CAI, a small on-device helper, is available with no key.

Three ideas, in order

  1. Local-first. Chats, settings, keys and profiles live in localStorage. Clearing site data is the nuclear option, and it is yours to press.
  2. Bring your own key. By default, requests go from your tab to the provider. An optional trusted backend can relay a key for each request without persisting or logging it in the function code.
  3. Real agent loop. When tools are on, the model can call calculate, current_time and search_history; every call is shown as a card with its arguments, result and runtime.
  4. On-device when you need it. Eltes CAI-1 answers chat, Eltes questions, model choice, arithmetic, units and dates in this tab. No key, no network, and it is explicit about what it does not know.

What changed in v3

Areav3 behaviour
RepliesLive streams only. A missing key produces a connect card; failures produce typed error cards with retry. CAI answers locally and labels itself.
ChatDark-blue theme with a block field that moves with the scroll. Step timeline, tool cards, per-message chips, first-token latency, tokens and tok/s.
Models36 real models across 13 providers, including Claude Sonnet 5.5, DeepSeek V4.1, NVIDIA NIM and three Eltes CAI models.
AccountsSign up or in with OpenAI, Anthropic or DeepSeek, or keep a local profile. GitHub sign-up is gone.
BrandGreen cloud mark — one eye closed, one open — across the site, favicon, app icon and maskable manifest icon.
DownloadsA portable Windows package with eltes.bat, a Start-Eltes helper and the whole static site.
Static by design. Eltes is plain HTML, CSS and JavaScript. Host it on any static host, or open it from a local server. There is nothing to compile and no secrets in the bundle.

Quickstart

From a blank tab to a live answer, with one provider key.

Open the workspace

Go to app.html. No install and no sign-in. An account is optional and only adds a profile.

Connect a provider

Press Connect an account, choose OpenAI, Anthropic or DeepSeek, and save the key. Or open Settings → API keys. The pill in the top bar turns green when at least one key is present. No key yet? Pick Eltes CAI-1.

Pick a model

Use the model button or ⌘M. Models without a key show a needs key badge; star the ones you use most and they move to the top.

Send a message

Type and press Enter. Tokens stream in as they arrive; press the stop button to keep a partial answer. Metrics appear under the reply when it finishes.

terminal — run Eltes locally
# clone the repository
git clone https://github.com/gefrus112/eltes
cd eltes

# any static server works; there is no build step
python3 -m http.server 4173

# open http://localhost:4173
No key handy? Eltes CAI-1 runs in this tab with no key. For an open-weight model, run Ollama and point Eltes at http://localhost:11434/v1 under Custom endpoints.

Accounts

An Eltes account is a profile plus a set of provider connections. It stores a name, an email, the provider that created it and — when you connect one — a provider key. There is no password, no session cookie and no email delivery. The profile is written to eltes.account.v1; provider keys live in eltes.settings.v1.

Create or sign in

Open auth.html. Sign up with OpenAI, Anthropic or DeepSeek, or create a local profile with a display name and email. Signing in restores the profile already in this browser. Because there is no Eltes server, a local email is a label, not a credential.

ProviderWhat “connect” does on a static copyWhat it does with a host
OpenAIValidates the key against /v1/models, then stores it locallyRedirects to /openai/start and returns a profile
AnthropicValidates against /v1/models with the browser-access headerRedirects to /anthropic/start and returns a profile
DeepSeekSaves the key; verification is best-effort because CORS variesRedirects to /deepseek/start and returns a profile
Local profileName + email, stored in this browser onlySame — no hosted identity required

Hosted OAuth contract

A static page cannot hold a client secret, so the hosted path is a contract rather than a fake success state. Set the endpoint before the auth scripts load:

auth.html — before the scripts
<!-- Only when a real auth backend exists -->
<script>
  window.ELTES_CONFIG = {
    authEndpoint: 'https://auth.example.com'
  };
</script>

With authEndpoint set, a provider button redirects to:

redirect shape
# provider is openai, anthropic or deepseek
GET https://auth.example.com/<provider>/start
    ?return=<the full auth.html URL>
    &mode=signup

# your backend completes OAuth, then returns the user to:
https://eltes.example/auth.html?account=<base64url(profile)>

# profile
{
  "name": "Ada Lovelace",
  "email": "ada@example.com",
  "provider": "openai",
  "avatarUrl": "https://example.com/ada.png"
}

The page decodes the profile, writes it locally, clears the parameter and shows the signed-in state. Avatar URLs are restricted to https:. An error=… or provider_error=… parameter shows a failure message instead, so a cancelled login never looks successful. code and state are stripped from the address bar after the callback.

Never put a client secret in this page. Anything shipped to the browser is public. Without an endpoint, the connect panel asks for a real key and stores it locally — it does not claim an OAuth session.

API keys

Keys are read from localStorage at request time and are excluded from exports. In direct mode, OpenAI-compatible providers receive Authorization: Bearer …; Anthropic receives x-api-key and anthropic-version. With the optional proxy, the browser sends the key in a request header to the configured backend, which forwards it using the provider's required authentication. Eltes function code does not persist or log it; the key still transits the backend platform.

ProviderKey prefixWhere to get it
Anthropicsk-ant-…console.anthropic.com → API keys
OpenAIsk-proj-…platform.openai.com → API keys
GoogleAIza…aistudio.google.com → API key
Z.ai · GLMaccount tokenz.ai → API keys
DeepSeeksk-…platform.deepseek.com
xAIxai-…console.x.ai
Qwen · Alibabask-…Model Studio console
MistralAPI keyconsole.mistral.ai
Groqgsk_…console.groq.com
OpenRoutersk-or-v1-…openrouter.ai/keys
NVIDIA NIMnvapi-…build.nvidia.com

What a request looks like

OpenAI-compatible streaming
POST {baseUrl}/chat/completions
Authorization: Bearer <your key>
Content-Type: application/json

{
  "model": "gpt-4.1",
  "stream": true,
  "messages": [{ "role": "user", "content": "Hello" }]
}

Rotating and removing keys

  • Keys can be replaced at any time under Settings → API keys; saving overwrites the old value immediately.
  • Removing a key disables that provider's models until a new one is saved.
  • Exports never include keys. Backups are safe to share; localStorage is not.
Least privilege. Use a dedicated key per device, set a spend limit at the provider, and revoke it from the provider dashboard if a machine is shared.

Providers & CORS

By default, providers are called directly from the page, which requires permissive provider CORS headers. Some providers allow it; others do not. If a direct call is blocked, Eltes shows a network/CORS error with retry guidance. You may instead configure the optional Vercel/local backend to relay supported hosted-model requests; review the proxy trust and privacy notes before using it.

ProviderBase URLDirect browser calls
Anthropicapi.anthropic.com/v1Yes — sends anthropic-dangerous-direct-browser-access
OpenAIapi.openai.com/v1Yes
Google Geminigenerativelanguage.googleapis.com/v1beta/openaiYes
Z.ai · GLMapi.z.ai/api/paas/v4Usually
DeepSeekapi.deepseek.com/v1Varies by region
xAIapi.x.ai/v1Varies
Qwendashscope-intl.aliyuncs.com/compatible-mode/v1Varies
Mistralapi.mistral.ai/v1Varies
Groqapi.groq.com/openai/v1Yes
OpenRouteropenrouter.ai/api/v1Yes
NVIDIA NIMintegrate.api.nvidia.com/v1Yes
Eltes CAIin this tabNot applicable — no network request
Customyour URLDepends on your server

Error states you will actually see

StateWhat Eltes showsWhat to do
401 / 403“Provider rejected that key”, with Fix keyPaste a fresh key; the failed turn retries automatically after saving
429Rate limit or quota reachedWait, retry, or switch to another connected model
Network / CORS“Could not reach provider”Check the network, try another provider, or route through a proxy
404Model not available on this accountPick another model from the picker
No keyConnect card with the provider rowAdd a key or switch models — no fake answer is generated
Offline“You are offline”Reconnect and press retry
Optional proxy. Eltes can send a key to a Vercel/local backend over HTTPS for one request; the function code does not persist or log it. The backend operator and platform still process it, so configure only a backend you trust. Direct browser-to-provider mode remains available when the backend URL is blank. See deployment steps.

Custom endpoints

Anything that speaks OpenAI's /chat/completions can back Eltes: Ollama, vLLM, LiteLLM, LM Studio, a Cloudflare Worker or your team gateway. Set a base URL, a model id and — only if your server requires one — a token.

  1. Open Settings → API keys → Custom endpoint.
  2. Enter the base URL, including /v1 when that is what your server expects.
  3. Enter the model id exactly as the server reports it.
  4. Pick Custom endpoint from the model picker and send a message.
Ollama — OpenAI-compatible
# 1. run a model
ollama run llama3.1

# 2. in Eltes → Settings → Custom endpoint
Base URL   http://localhost:11434/v1
Model id   llama3.1

# Ollama allows browser origins from localhost by default.
# For another device, set OLLAMA_ORIGINS to your static host.
OLLAMA_ORIGINS="https://eltes.example" ollama serve

When CORS blocks the browser

Configure the optional Vercel backend described in Self-hosting, or run Eltes with npm start for the local API during development. The proxy forwards the user's key for that request and only allows fixed provider targets. Do not paste a provider key into a source file, public static host, or shared deployment environment variable.

HTTPS pages cannot call HTTP endpoints. If Eltes is served over HTTPS, a plain http://localhost endpoint will be blocked by mixed-content rules. Serve Eltes locally for local models, or expose the model over HTTPS.

Models

HTML code fences include a sandboxed preview, copy and download actions. Preview scripts run in an isolated frame with network access blocked.

NVIDIA NIM uses https://integrate.api.nvidia.com/v1 and a key from NVIDIA Build. Catalog access and any free quota depend on NVIDIA's account and model availability; these models are not guaranteed to be free.

The catalogue ships 36 models across 13 providers. Each hosted entry is a real API target with its own context window, tier and capability flags. Nothing is simulated, so a hosted model only answers when its provider is connected. The three Eltes CAI entries run locally instead.

ProviderModelsBest at
Eltes CAICAI-1, CAI-1 Fast, CAI DocsOn-device chat, Eltes help, maths, units, dates
OpenAIGPT‑6 Sol, GPT‑6.1 Sol, GPT‑6 Luna, GPT‑4.1Reasoning, coding and vision
AnthropicClaude Sonnet 5.5, Opus 5.5, Haiku 5.5, Fable 5.1, Opus 4.5Code, long context, careful writing
DeepSeekV4.1 Flash, V4 ProCost, 1M context, multimodal
GoogleGemini 2.5 Pro, 2.5 Flash1M context, multimodal
Z.aiGLM-4.6, GLM-4.5, GLM-4.5 AirAgentic coding, low cost
xAIGrok 4, Grok 3Direct answers, reasoning
QwenQwen3 Max, Qwen3 Coder PlusBilingual, repository-scale code
MistralMistral Large, CodestralFunction calling, completion
GroqLlama 3.3 70B, Llama 4 ScoutVery high tokens per second
NVIDIA NIMLlama 3.3 70B, Nemotron UltraOpen models via NVIDIA-hosted NIM; key and model access required
OpenRouterAuto, Claude Sonnet 5.5, Gemini 2.5 Pro, GLM-4.6, DeepSeek Flash, Qwen3 CoderOne key, routing and fallbacks
CustomWhatever your endpoint servesLocal and private models

Eltes CAI — our own models

CAI (conversational agent intelligence) is a small deterministic model implemented in assets/js/cai.js. It runs inside the tab with no key and no network. It is accurate on its domain and explicit about its limits; it never pretends to browse.

ModelStrengthExample
Eltes CAI-1General on-device chat“Which model should I use for code?”
Eltes CAI-1 FastShorter answers, quicker pacing“Convert 68 °F to °C”
Eltes CAI DocsEltes setup, keys, accounts, downloads“How do I connect a DeepSeek key?”

CAI covers Eltes documentation, model recommendations from the live catalogue, arithmetic and percentages, unit and temperature conversion, the current date and time, word counts and a glossary of AI terms. Anything outside that gets an honest fallback with a suggestion to switch to a hosted model.

Real model streaming, including Claude

Eltes streams from provider APIs when Settings → General → Stream responses is enabled. Claude uses Anthropic’s native Messages API; OpenAI-compatible providers stream chat-completion events. Replies are never simulated for hosted models.

  • Save a valid provider API key in Settings → API keys. Eltes checks locally for a key before sending and opens a connect prompt if it is missing.
  • Claude Sonnet 5.5 uses Anthropic SSE and paints tokens as they arrive. OpenAI-compatible providers use SSE with a live cursor and first-token metrics.
  • 401/403, 429, model-not-found and CORS/network failures have separate retry guidance.
  • Eltes does not include hosted model credits or determine whether a provider account has free quota. CAI is the free, on-device option; hosted usage follows provider terms and billing.

Per-chat models

The model is stored on the conversation, not globally. Switch mid-thread and the next reply uses the new model while the history stays intact. New chats use the default model chosen in Settings → Models. Deep links such as app.html?model=glm-4-6 preselect a model from the landing page.

No silent fallbacks. If a hosted model needs a key, Eltes shows a connect card naming the provider. It does not quietly answer with something else.

Agent & tools

Tools are real function calls, not a scripted animation. Turn on Tools in the composer (or set it as the default in Settings) and the model may call one of three local tools. Eltes executes the call in the page, returns the result to the model, and lets it continue — up to four rounds.

ToolInputWhat it does
calculate{ expression }Evaluates arithmetic in a restricted sandbox — digits and operators only
current_time{ timezone? }Returns the current date and time, optionally in an IANA timezone
search_history{ query }Searches saved conversations locally and returns titles plus snippets

What the timeline shows

  • Thinking while the request is open, then streaming once tokens arrive.
  • Tool cards with the tool name, arguments, a running/done state and the runtime in milliseconds.
  • Metrics after the turn: first-token latency, total time, tokens in/out and tokens per second.
  • Model and provider chips on every assistant message, so a long thread with switches stays readable.

Tool calling support

Tools are only offered when the selected model advertises support. Models without tool support — the Eltes CAI family and completion models such as Codestral — are sent the plain conversation. If a provider rejects the tool schema, the error card reports it and retry without tools still works.

Nothing leaves the page for tools. Arithmetic, time and history search run locally in JavaScript. Only the model request and its tool results go to the provider.

Chats & export

Conversations are grouped into Today, Yesterday, Previous 7 days, Previous 30 days and Older. Pinned chats sit on top. Every row has a menu with rename, pin, clear, export and delete.

Editing and retrying

  • Edit a user message to rewind the thread to that point and put the text back in the composer.
  • Retry re-runs the last turn with the current model; the failed turn is kept out of the history.
  • Copy works on replies and on each code block independently.
  • Feedback thumb buttons are stored locally and never uploaded.

Exports

FormatContainsUse it for
MarkdownFull transcript with model, tool runtimes and token countsDocs, issues, sharing in a repo
JSON (one chat)Raw conversation objectDebugging or your own tooling
JSON (all chats)Chats and settings, keys strippedBackups and moving devices
Backups never include keys. Import merges chats and settings into this browser while keeping the keys already there.

Settings

Open with ⌘, or the gear in the top bar. Settings are stored in eltes.settings.v1 and apply instantly.

PanelControls
GeneralDefault model, streaming, send key, tools by default, density, reduced motion, timestamps, metrics
API keysProvider keys, reveal/save/remove and provider key test through configured proxy, Vercel/local backend URL, custom model endpoint
ModelsStar favourites, choose the default model for new chats
AccountProfile, display name, sign out, delete profile, plan
DataChat count, storage meter, export all, import, delete all chats
AboutVersion, model count, shortcuts and links

Storage meter

The sidebar footer shows how much of the browser's local storage the app is using. The meter is deliberately conservative: browsers commonly allow about 5 MB per origin, and large attachments or very long threads consume it fastest.

Keyboard shortcuts

Command palette — chats, models, actions⌘K
Model picker⌘M
Toggle the sidebar⌘B
New chat⌘N
Settings⌘,
Focus the composer⌘/
Send / newline↵⇧↵
Close dialog or menuesc

On Windows and Linux, use Ctrl wherever ⌘ is shown. The interface relabels the modifier automatically.

Downloads

Everything Eltes ships is static. The Windows download is the same site wrapped in a portable launcher, so the only requirement is a way to serve files locally.

eltes-windows.zip
eltes-windows/
├── eltes.bat           # double-click to launch
├── Start-Eltes.ps1     # the actual server + browser open
├── README-WINDOWS.txt
├── index.html
├── app.html
├── auth.html
├── docs.html
└── assets/ …           # css, js, fonts, icons

What the launcher does

  1. Changes into its own folder, so it works from any drive or USB stick.
  2. Finds python, py -3 or node.
  3. Starts a static server bound to 127.0.0.1:4173.
  4. Waits for the port, then opens your default browser at the workspace.
  5. Leaves the server running until you close the console window.
It is a text file. Open eltes.bat in Notepad before running it. There is no installer, no elevation prompt and no outbound connection; the server listens on localhost only.

Optional Start-menu shortcut

cmd
:: create a shortcut in the Start menu
eltes.bat --shortcut

:: use a different port (default 4173)
eltes.bat --port 8080

macOS and Linux

Clone or unpack the same files and serve the root:

terminal
python3 -m http.server 4173
# then open http://127.0.0.1:4173/app.html

Install as an app

site.webmanifest declares standalone display, a dark theme colour and maskable icons at 192 and 512 px. Chrome, Edge and Safari can install the page as a window with the green-cloud icon; there is no Electron wrapper and no auto-updater.

Update by replacing files. Copy a new build over the old folder and keep localStorage. Chats, keys and your profile live in the browser, not in the download.

Pricing

The static Eltes workspace is free. Hosted replies require your own API key and may incur provider charges at its published rates. Eltes does not supply free hosted credits. CAI runs on-device without a key or per-token cost. There is no markup, subscription or card on file. A hosted tier with managed keys is in design; the pricing section shows pricing not announced because nothing is purchasable yet.

PlanStatusWhat you get
BYOKAvailable now · $0Every model, tool loop, local history, accounts, exports. You pay the provider.
HostedIn designManaged keys and sync without handling credentials. Pricing not announced.
Self-hostedAvailable now · $0Clone the repo and serve the static build wherever you like.
No bait pricing. Nothing on the site can take a payment. When the hosted plan is real, the pricing page will show the amount, the limits and the cancellation path before checkout.

Self-hosting

Publish with GitHub Pages

The repository’s .github/workflows/pages.yml workflow assembles and deploys only the static site files to GitHub Pages. Subsequent updates publish through the repository workflow. GitHub Pages serves HTML, CSS, JavaScript, images and the Windows download; it does not run the API backend, store secrets, proxy model requests, or grant provider free-tier access.

Without a configured proxy, users save keys in their browser and provider APIs receive requests directly from that browser, subject to provider CORS. Eltes also includes Node-based local API routes for development and separate Vercel functions for deployment.

Run the local site and API

With Node.js 18 or newer, run npm install and npm start, then open http://localhost:4173/app.html. This serves the static site and the three local API routes. The server binds to 0.0.0.0 for development-preview compatibility and has no user authentication; keep it on a trusted network. Use HOST=127.0.0.1 npm start to bind only to loopback. A Python static server serves only files, so it does not provide key testing or proxy routes.

Deploy the optional proxy to Vercel

  1. Import the repository into Vercel with the project root as the root directory. The functions are in api/; vercel.json sets a 60-second function limit.
  2. Set the project environment variable ELTES_ALLOWED_ORIGINS to exact comma-separated browser origins, without paths or trailing slashes. Example: https://gefrus112.github.io,http://localhost:4173.
  3. Deploy, then in Eltes Settings → API keys → Optional Vercel/local backend, enter the Vercel deployment origin and use Save and test.

The available routes are /api/health, /api/key-check, and streaming/non-streaming /api/chat. The backend only contacts fixed provider hosts and allowlisted provider/model pairs; it never accepts an arbitrary upstream URL. CORS origin checks are not authentication; these routes are public to non-browser clients unless you add access controls. Do not offer an unprotected shared proxy to untrusted users without adding authentication and rate limiting. The key transits the backend for each call; the function code does not persist or log it, but the platform and provider process the request. Use only a deployment you trust and set provider spending limits. Static hosting and Vercel backend deployment are separate; this documentation does not mean a deployment has already occurred.

repository layout
eltes/
  index.html            # marketing home
  app.html              # the workspace
  auth.html             # local accounts
  docs.html             # this page
  assets/
    css/                # theme, landing, app, docs, auth
    js/                 # models, brands, icons, app engine
    fonts/              # Inter + JetBrains Mono, self-hosted
    img/                # favicon and social card
  site.webmanifest
  LICENSE · NOTICE.md

Deployment checklist

  • Serve over HTTPS in production. The clipboard API and some provider endpoints require a secure context.
  • Keep every asset path relative so the app works from a subdirectory.
  • Do not add analytics that read localStorage; it holds keys.
  • If you add a content security policy, allow connect-src for each provider you use.
Sharing with a team? Host the static build, then give each person their own keys. There is no shared key store by design.

Privacy

Eltes includes no analytics, telemetry, or third-party font requests. In direct mode, a model request goes from your browser to the selected provider. If you configure the optional backend, key checks and model requests transit that backend; the function code does not persist or log provider keys, but the backend platform processes request metadata and the key while handling the call.

What Eltes stores

eltes.chats.v1 — conversations and per-message metadatalocal
eltes.settings.v1 — provider keys, backend URL, model default, preferenceslocal
eltes.account.v1 — optional profilelocal
eltes.waitlist.v1 — pricing waitlist entries, if you joinlocal
No cookies, no fingerprinting, no session replaynone

What providers see

Your prompt, the conversation history sent with it, and whatever tool definitions or results are included in that request. That is exactly what any chat client must send to get an answer. Eltes adds no account identifier, because it does not have one to add.

Deleting data

Use Settings → Data to delete all chats, or Account → Delete profile to remove the profile. Keys can be removed individually. Clearing site data for the origin removes everything at once.

FAQ

Why is there no demo mode?

A simulated answer is indistinguishable from a wrong one. Eltes would rather show a connect card or a typed error than pretend a model replied. If you want to try the interface without a paid provider, run Ollama locally and use a custom endpoint.

Do I need an account?

No. Accounts are optional profiles. The workspace, keys, history and exports work without one. Create a profile only if you want a name and avatar attached.

Is it safe to paste an API key into a web page?

Only on a page you trust and control. Eltes is static and self-hostable, so you can audit every line and serve it yourself. Keys sit in localStorage, which any script on the origin can read — do not load untrusted third-party scripts alongside it.

Why does a provider fail with a network error?

Usually CORS. The provider must allow the browser origin in direct mode. See Providers & CORS, or configure the optional Vercel/local backend in Settings → API keys.

Which models can use tools?

Models with tool support in the catalogue: Claude 5.5 and 4.5, GPT‑6 Sol/Luna, GPT‑4.1, Gemini 2.5, GLM-4.x, DeepSeek V4.1/V4, Grok, Qwen3, Mistral Large, Llama 3.3/4 and most OpenRouter routes. The Eltes CAI models run their own local intents and Codestral is sent the plain conversation.

Can I use it offline?

Yes, partly. Eltes CAI-1 answers chat, Eltes questions, arithmetic, units and dates with no network at all. Hosted models need a connection, unless you point a custom endpoint at a model running on your machine. The Windows launcher serves the whole site locally.

Can I sign up with OpenAI, Anthropic or DeepSeek?

Yes. The account page offers all three. On a static copy, connecting means validating and storing a real provider key in this browser. On a hosted deployment with ELTES_CONFIG.authEndpoint, the same buttons start a real OAuth redirect. GitHub sign-up has been removed.

What is the Windows .bat file?

eltes.bat is a readable launcher included in eltes-windows.zip. It finds Python or Node, starts a static server on 127.0.0.1:4173 and opens the workspace. It does not install a service, touch the registry or need admin rights.

What happens to my chats if I clear site data?

They are gone. localStorage is the only copy. Export a JSON backup from Settings → Data first if the thread matters.

Ready to connect a real model?

Bring one key. Eltes does the rest — streaming, tools, metrics and history that stays here.

Open the workspace