neuron-explorer
Qwen3.5‑4B 전용 조향형 뉴런 탐색기, 모든 MLP 뉴런을 밀어 결과를 보관·탐색
PromptSpend는 매일 업데이트되는 카탈로그를 통해 제공자별 LLM API 비용을 비교하고, 무료·오픈소스이며 계정·분석이 필요 없다
Compare LLM API costs across providers, from a catalog that re-checks itself every morning. Free, open source, no accounts, no analytics.
개발 도구TypeScript · CSSGitHub @AndrewAvery7온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기LLM pricing that shows its work: every price carries its source and the date it was last confirmed, re-checked against the vendors every morning. A web calculator, an MCP server, a VS Code extension and a free keyless API.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Know the tab before you build.
Estimate, compare and understand what an AI feature will cost — from a catalog that re-checks itself every morning, so the numbers are never a year out of date.
→ Open PromptSpend
· free · open source · no accounts, no tracking
· Writing: What LLM Cost Calculators Get Wrong
· August 2026 Price Movement Report
2 minutes 8 — press play, and hit 🔊 to unmute (GitHub starts videos silent).
·
Download the MP4README 전문 보기 ↗https://github.com/user-attachments/assets/6bfecd10-84a9-408b-b08c-ff9481648692
Every LLM cost calculator on the web has the same failure mode: it is a snapshot. Someone builds it, hard-codes a dozen model prices, and within a few months the entire premise is wrong — the models it compares have been superseded and the prices it quotes no longer exist.
PromptSpend is built the other way round. The pricing pipeline is the product; the calculator is what sits on top of it. Every morning a GitHub Action re-fetches the catalog from independent sources, merges them under an explicit trust order, runs sanity checks, and either commits the result or opens a pull request for a human. Capture patterns are family-level, so a brand-new model version is picked up automatically without anyone touching code.
Opt-in, and off unless a deployment is configured for them. Browser push stores nothing personal — a push subscription is an opaque URL the browser issues. Email is double opt-in with one-click unsubscribe, and stores your address, the models you follow, and the date you asked; nothing else. Either channel can watch the whole catalog or just the models you pick.
The delivery service is a Cloudflare Worker in worker/, with the push payload encryption
written out against RFC 8291 and checked byte for byte against the RFC's own worked example.
docs/ALERTS.md has the architecture, the cost model and the domain cutover.
| Output is priced separately | Output typically costs 3–5× input. Averaging the two, as many calculators do, understates most real workloads. |
| Chat history compounds | Turn N re-sends turns 1…N−1 as input, so conversation cost grows with the square of the turn count. |
| Tokenizers differ per family | The same pasted text is counted with each model's own tokenizer — exactly (js-tiktoken, run in your browser) for OpenAI-family models and with a clearly labeled calibrated ratio elsewhere. |
| Caching is not free | Cache writes cost 1.25× input at both OpenAI and Anthropic. Counting only the cheaper reads reports a saving your invoice will not have, so writes are billed and caching is off by default. |
| Long context costs more | Above 272K input tokens OpenAI bills the whole request at 2× input and 1.5× output. Tiers apply per request, so a conversation can cross over partway through. |
| Reasoning tokens are billable | A multiplier for hidden thinking tokens, because the visible answer is not what you pay for. |
| Promotional pricing expires | Introductory rates apply only inside their window, and the engine takes a date. |
| Assumptions are visible | Every non-published number used in a calculation is listed under the results, not buried — and so is what the prices do not cover. |
| Impossible scenarios are named | A request that will not fit the context window, or a response past the output ceiling, is flagged rather than priced as if it would work. |
┌─────────────────────────┐
LiteLLM catalog ──┤ │
│ allowlist → merge → │──→ public/data/pricing.json ──→ the app
OpenRouter API ───┤ validate → diff │
└───────────┬─────────────┘
data/pricing-overrides.json ──┘ └──→ docs/pricing-changelog.md
(hand-verified, wins)
The trust ladder, in order:
data/pricing-overrides.json) — win every conflict.A diff is committed and deployed automatically, flags included: there is no human gate on publication,
on purpose, because a flag that held the whole catalog once left the site's dates two days behind. A
newly raised flag publishes with everything else, marks that row disputed on the site, and opens an
issue for review — a long-standing disagreement does not re-open one every morning. A run that loses a source or trips a size
guard is degraded: it publishes nothing, records why in public/data/sync-status.json, and fails
loudly. Either way the change lands in docs/pricing-changelog.md.
Nothing disappears on one bad morning. A model missing from the feed is kept and marked stale, not
deleted; retiring one for good is a deliberate edit to data/models-allowlist.json.
Rung 1 is worked by hand, and the split is published rather than blurred. Every row says which rung it
came from, and rows read against a vendor's own page carry the URL that was read and the date it was read.
Most of the catalog is now vendor-sourced — but not all of it, because some vendors do not publish a
pricing page that lists their own models, and the honest answer there is to leave the row labeled
litellm rather than launder an aggregator's number into a first-party claim. The models this currently
affects are named in docs/DEFERRED.md. A number is only worth what its worst source is,
so the site shows you the source per row instead of an average you cannot inspect.
A daily job reads the live site — not the copy in this repository — and raises an issue if the published catalog is more than two days old. That distinction is the whole point. Between a price moving upstream and you seeing it, four things can fail: the sync errors, the sync cannot commit its result, the deploy fails after a green sync, or the CDN serves a stale artifact. Checking the file in git catches the first of those. Fetching what the site actually serves catches all four.
It exists because the sync once failed at its publishing step and nothing said so; the site quietly served a day-old catalog until someone happened to look. A project that claims its numbers are never a year out of date should be the first to know when they are.
The site shows prices last changed and sources last checked separately, because they answer different questions. A quiet week in the market makes the first date age while everything works perfectly; a broken scheduler looks exactly the same if you only publish one date. The second comes from a health manifest written on every run, successful or not:
https://promptspend.com/data/sync-status.json
Right now the first of those reads not yet recorded, and that is correct rather than broken. No vendor has moved a price since this catalog's history began on 2026-08-01, so there is no date to show — and the alternative, quietly displaying the last build date, would announce a price change every morning nothing happened. An empty field you can trust beats a populated one you cannot.
The second is now a state and not just a date: the chip on the results panel is green while the sources were checked within a day, blue at two days, amber past the window the freshness monitor tolerates or after a degraded run, and outlined-grey when the manifest could not be loaded at all. That last state exists on purpose. A status light that reads "fine" when its own evidence is missing is precisely the failure the monitor was built to catch.
Keeping "prices last changed" honest means the pipeline has to tell apart three events that all look like a diff:
| What happened | lastChanged | |
|---|---|---|
| Price change | Same source, different number. The vendor repriced. | stamped |
| Coverage | A field went from absent to present. We started recording a rate that was always offered. | untouched |
| Correction | The number moved in the same run its source URL did. We had been reading the wrong page. | untouched |
Only the first is news. Conflating them is not hypothetical: reading x.ai's real pricing page instead of
its model list once gained a long-context tier and restated a cached-input rate, and the catalog stamped
both as price changes — putting PRICES CHANGED 2026-08-06 on the busiest panel of the site with no
vendor having touched a rate. Suppressing corrections can hide a genuine same-day move, and that trade is
deliberate: on a catalog whose whole claim is provenance, announcing a change nobody made costs more than
missing one by a day.
There is a free, keyless, CORS-open API at promptspend.dev — no account, no key, no rate limit:
curl https://promptspend.dev/v1/prices # flat rows: the numbers only
curl https://promptspend.dev/v1/models/gpt-5 # one model, in full
curl https://promptspend.dev/v1/prices.csv # the same rows, for a spreadsheet
Filters: ?provider=, ?status=, ?aliases=include. Every response carries
X-PromptSpend-Generated-At, and OpenAPI 3.1 lives at
/openapi.json. See docs/API.md.
[](https://promptspend.dev/)
Swap the model id for any id from /v1/models. The badge is drawn
fresh on every fetch — no cache — so the date it shows is always the day that price was last confirmed.
claude mcp add promptspend -- npx -y @promptspend/mcp
Or with nothing to install: add https://promptspend.dev/mcp as a custom connector in Claude.ai or
ChatGPT (claude mcp add --transport http promptspend https://promptspend.dev/mcp in Claude Code).
Other pricing MCP servers exist and index more models than this one. What none of them do is tell you where a number came from and when it was last confirmed — the competing server's own documentation says only that pricing "is updated regularly", with no verification date per price. That gap is the reason this exists.
It matters more to a model than to a person. Someone reading a web page sees the interface around a figure and calibrates. A model handed a bare number repeats it with whatever confidence the sentence implies. Given the source and the date it can say "as of 1 August, per OpenAI's pricing page" — and when two sources disagree it is told so, rather than being handed a number somebody picked.
Three tools, deliberately. estimate_cost is the one a price lookup cannot provide: it runs this
repository's cost engine, imported rather than reimplemented, so it accounts for compounding
conversation history, cache writes, long-context tiers and reasoning tokens — and cannot report a
figure that disagrees with the calculator, because it is the same code. A test asserts that.
get_price also takes a past date (as_of) and answers from the published price history, and
estimate_cost also prices measured usage totals, such as a month from a usage export.
And because MCP tool definitions load into your context on every turn, the server's own overhead is measured, budgeted at 1,200, checked in CI and published: ~897 tokens. Nothing else in the ecosystem appears to publish its own footprint. See mcp/README.md. If even that is too much, the same three tools come as an Agent Skill that loads only when a price question comes up: see skills/.
A GitHub Action that fails the build when a model your code calls changes price or is retired. It
records the rates in force in a committed promptspend.lock.json, like a package lockfile, and
compares on every run:
- uses: AndrewAvery7/promptspend/github-action@action-v1
The same catalog, on the line of code that chooses the model.
response = client.messages.create(
model="claude-sonnet-4-6", # $3 / $15 per M · max out $0.061
max_tokens=4096,
)
A linter for model choice rather than a calculator in a sidebar — a calculator in an editor is
only this website with worse ergonomics. What an editor can do that a web page cannot is notice
things: a nearby max_tokens becomes the output ceiling in money, a cap above what the model can
emit is named rather than priced as though it would work, deprecated and disputed rows reach the
Problems panel, and an Explorer view lists every model the repository calls, dearest first.
Everything it says is Information severity, never a warning. None of these are mistakes and the extension has no idea what the code needs. The cheaper-model suggestion is off by default for the same reason the value map's capability axis is labeled illustrative: it is an opinion, where the rest are facts.
code --install-extension promptspend.promptspend
Or search PromptSpend in the Extensions pane. It is on Open VSX too, which is where Cursor, Windsurf and VSCodium look.
Same rule as everywhere else — no bundled prices. If the catalog cannot be reached it says so and shows nothing, and the status bar carries the generation date at all times. See vscode/README.md.
Native apps for iPhone and Android, free on the App Store and Google Play: paste a sample conversation, compare up to four models, and see the cost per conversation, day, month and year from the same catalog. Pasted text is processed on the device and never uploaded. Both are described at promptspend.com/app; the source is in apps/mobile/.
Or read the file the API reads. The catalog is plain, versioned JSON with a stable shape:
https://promptspend.com/data/pricing.json
{
"schemaVersion": 2,
"generatedAt": "2026-08-02T02:27:22.781Z",
"providers": [{ "id": "openai", "name": "OpenAI", "country": "US", "pricingUrl": "https://…" }],
"models": [
{
"id": "gpt-5.6-terra",
"providerId": "openai",
"displayName": "GPT-5.6 Terra",
"status": "current", // current | legacy | deprecated
"contextWindow": 1050000,
"pricing": {
"input": 2, // USD per 1M tokens
"output": 12,
"cachedInput": 0.2,
"cacheWrite": 2.5, // writing costs *more* than sending
"batchDiscount": 0.5,
"longContext": { "thresholdTokens": 272000, "input": 4, "output": 18 },
},
"tokenizer": { "kind": "tiktoken", "encoding": "o200k_base" },
"provenance": {
"source": "vendor", // vendor | litellm | openrouter
"lastVerified": "2026-08-01", // when it was checked — always present
"lastChanged": "2026-08-01", // optional: when the number last moved
"verifiedUrl": "https://developers.openai.com/api/docs/pricing",
},
},
],
}
Optional fields worth knowing: aliasOf marks an id that routes to another model (so it is not counted
twice), provenance.stale marks a row upstream has stopped listing, and provenance.needsReview plus
reviewNote carry an unresolved disagreement and both numbers involved.
provenance.lastChanged is optional too: it is present only on a model whose rate has actually moved since
this catalog's recorded history began on 2026-08-01, and absent otherwise. Read its absence as "no change
on record", never as "unknown freshness": lastVerified answers that, and it is always there. A field that
reported the last sync instead would read "changed today" every morning, which is the one failure a
provenance catalog cannot afford — so it stays empty until a rate actually moves.
npm ci # `ci`, not `install` — this repo has a lockfile and CI honors it
npm run dev # http://localhost:5173
npm run verify # exactly what CI runs, and what the deploy gate runs
npm run sync:pricing:dry # see what today's sync would change, without writing
verify is typecheck, lint, format check, an encoding check, tests with coverage thresholds, the
published test counts, the published page counts, a production build, catalog schema validation, the
bundle budget, the Content Security Policy and the SEO checks. The deploy workflow calls the same reusable workflow CI does and
publishes the artifact it produced, so a commit that fails any of them cannot reach the live site.
It does not run the other packages' suites — CI has a job each for api/, mcp/, updates/, vscode/
and worker/. See CONTRIBUTING.md.
src/lib/engine/ the cost engine — pure functions, no React, heavily tested
src/receipt/ the transparent Receipt object, page and versioned instruction contract
receipt/ the second Vite HTML entry, published as /receipt/
src/lib/tokenize/ exact tokenizer (lazy-loaded) + calibrated ratios
src/lib/pricing/ catalog schema, validation, lookups
src/lib/alerts/ browser-side push and alerts API client
src/components/ the four views
src/lib/seo/ the generated pages: slugs, page model, HTML renderer
scripts/ the daily sync pipeline (scripts/lib is unit-tested)
data/ capture patterns and hand-verified overrides
public/data/ the published catalog the app reads
public/sw.js service worker — push display only, no offline cache
worker/ the alerts API (Cloudflare Worker, own package and tests)
api/ the public pricing API on promptspend.dev (own package and tests)
updates/ the app's self-hosted over-the-air update server (own package and tests)
src/state/ the scenario hook, and the URL it mirrors itself into
tests/ the browser suite: Playwright at four viewports, plus axe
tools/ the promo pipeline — capture, render, stitch
mcp/ the MCP server — imports the engine above, so it cannot disagree with it
vscode/ the VS Code extension — imports it too, for the same reason
Beyond the calculator and Receipt, the build writes 374 crawlable pages — one per model, one per provider, and a curated set of head-to-heads — from the same catalog and the same cost engine. See docs/PAGES.md.
Cobalt on a cool-paper canvas, with a distinct set of money colors that never change with branding:
green means savings, red means this option costs more. The input/output chart pair is validated for
color-vision deficiency in CI — src/lib/palette.test.ts simulates protanopia and deuteranopia and
fails the build if the two marks stop being distinguishable.
src/lib/contrast.test.ts reads tokens.css directly and fails the build if any accent, on any theme and
any canvas, drops below 4.5:1 against a surface it can appear on. Every interactive target is at least
24×24 (44×44 on touch), no text renders below 12px, and there is no horizontal page scroll from 320px up.
Keyboard navigation throughout — including every point on the value map, which is a real button — focus is
returned when a dialog closes, prefers-reduced-motion is respected in JavaScript as well as CSS, and
there is a Ctrl/Cmd+K command palette.
| Document | What is in it |
|---|---|
| docs/ARCHITECTURE.md | How the pipeline, the engine and the state layer work, and why each is shaped that way |
| docs/TESTING.md | What the 1759 tests cover, the uneven coverage thresholds, and what the suite deliberately does not cover |
| docs/TROUBLESHOOTING.md | "The estimate does not match my bill", flagged prices, missing models, running it locally |
| docs/PAGES.md | The 374 generated pages: what is built, why the comparison set is curated, and the IndexNow pipeline |
| docs/SEO_PROGRAM.md | The search baseline, the 90-day plan written before the results, and the dated change log |
| docs/API.md | The public pricing API on promptspend.dev — endpoints, why it fetches rather than bundles, going live |
| docs/DOMAINS.md | What each hostname serves and why, plus the cutover runbook and rollback |
| docs/ALERTS.md | The price-alerts Worker — push and email architecture, the cost model, the domain cutover |
| docs/pricing-changelog.md | Every price change the daily sync has published, written by the pipeline itself |
Adding a model is usually a one-line change. See CONTRIBUTING.md, or open a model request and someone will pick it up.
Not a code change? [email protected]. Security reports go to [email protected] or GitHub's private vulnerability reporting — see SECURITY.md.
The three rules that are not up for negotiation, because breaking any of them turns an estimator into a guess with good typography:
The point of this section is that it is longer than it needs to be. An estimator that hides its edges is just a confident guess.
Nothing you type or paste leaves your browser. No accounts, no ads. Fonts are self-hosted. One image is not: the footer's LaunchNest listing badge loads from launchnest.io (their directory requires it), with no referrer, so LaunchNest's server sees a visitor's IP address but not which page they were on.
Google Analytics is paused. From 2026-10-24 to 2026-10-29 the website loaded Google Analytics 4 and showed a small notice saying so. It is switched off (GOOGLE_ANALYTICS_ENABLED in src/lib/analytics/config.ts) because no Google Analytics account exists to receive the data: nothing from Google loads, no notice shows, the page policies name none of Google's hosts, and a visitor who still holds its cookies from those days has them cleared the next time they open the site. The code, its tests and its safeguards stay in place so it can return (src/lib/analytics/): it is sent the page's site and path only — never the query string or #fragment, where the scenario and alert tokens live — with Google signals and ad personalization off, and nothing anyone types, pastes or enters in a form. It runs only on promptspend.com and never when the browser sends Global Privacy Control. Turning it back on means a new property and Measurement ID, the switch, and the privacy page, this file and SECURITY.md rewritten first.
The website counts visits with Cloudflare Web Analytics, a cookieless beacon that reports a page's address
(without its query string or fragment), referrer, country and load timings to promptspend.com's own
/cdn-cgi/rum; it never sees pasted text. The apps, the VS Code extension, the MCP server and the
API carry no analytics. Pasted prompt text is tokenised in your browser, deliberately excluded from the
shareable URL, held in a bounded in-memory cache, and gone when you close the tab. localStorage holds
only interface choices: your theme, accent and background, whether you dismissed the welcome and apps
banners (an earlier answer to the analytics notice may remain; it does nothing now).
Price alerts are the one exception, and only if you opt in. They are a feature you have to switch on, and they are the only reason this project has a server that stores anything (a Cloudflare Worker — docs/ALERTS.md); the pricing API (including the hosted MCP endpoint) stores nothing but Cloudflare's request logs (kept up to seven days), and the apps' update server has its logging switched off. Precisely what changes:
connect-src for that one API origin and, whenever an API is
configured, script-src, connect-src and frame-src for Turnstile's challenges.cloudflare.com
(whether Turnstile is actually required is decided at runtime, so the build permits it). Beyond
that, the remote origins are img-src for the LaunchNest badge, script-src for the Cloudflare
beacon (which posts only to this site). While Google Analytics is paused (since 2026-10-29) the policies name none of Google's hosts; when it runs they name www.googletagmanager.com for gtag.js and www.google-analytics.com, region1.google-analytics.com and region1.analytics.google.com for its reports, each named rather than wildcarded. That connect-src line is what stops a compromised dependency exfiltrating a pasted prompt, so it is generated from configured values rather than hand-maintained, and npm run check:csp fails on any origin it does not list. While Google Analytics runs, admitting Google's collector is a real cost — a script that got onto the page could post to an analytics account of its own — accepted on 2026-10-06 for visit counts.invocation_logs is off) and its own messages log counts and error types, never an
address. The public pricing API keeps Cloudflare's request logs, retained for up to seven days (Cloudflare's
published maximum), because
its addresses carry no secrets and they are how faults get diagnosed.A deployment with no API configured — which is what this repository builds by default — leaves the alerts API and Turnstile out of its policy (the analytics and badge origins above stay) and says on screen that alerts are not switched on, rather than rendering a form that cannot work.
See SECURITY.md. Wrong prices are treated as the most serious class of bug this project can have, and are explicitly in scope for a report.
MIT — see LICENSE. The self-hosted typefaces (Space Grotesk, IBM Plex Sans, JetBrains Mono) are SIL Open Font License 1.1.
| docs/PRICE_HISTORY.md | The same history as a citable CSV (CC0): its columns, units, and what the data does and does not claim |
| CHANGELOG.md | Changes to the application, as opposed to the data |
| docs/DEFERRED.md | Work proposed and deliberately not done yet, with the reason — a decision, not a gap |
| docs/FREE_TIERS.md | The free-tier pages: where the facts live, the daily quote check, and how to update a record |
| docs/ACCOUNTS_PLAN.md | The plan for user accounts: sign-in, where it must live, data, duties, phases. Not built yet |
| docs/SPONSORS.md | The sponsor policy: never in the data, always labeled, one slot per page. No sponsor yet |
| docs/AUTOMATION.md | What runs by itself while working on the project: the hooks, /ship, the reviewers, the test-count self-fix, and the Worker deploy |
| docs/PROMO.md | How the promo video is built from real screenshots, and how to rebuild it |
| mcp/README.md | The MCP server — pricing for coding agents, with the source and date on every number |
| vscode/README.md | The VS Code extension — prices on the line of code that chooses the model |
| CONTRIBUTING.md | Adding a model, the house style, and the rules that are not negotiable |
| SECURITY.md | What is in scope — including a wrong price, which is treated as the most serious class of bug |