BlvkWare BlvkWare. ← HALLUX

HALLUX

The hallucination ledger. A registry of identifiers that do not exist but that models confidently believe do.

Version 0.9 draft · BlvkWare · blvkware.dev


1. The problem

An agent writes pip install requests-oauth2-helper. The name is plausible, the agent is confident, and the package has never existed. One of three things happens next: the install fails and the agent burns a retry loop, the agent fabricates a workaround around a nonexistent API, or somebody has already registered that name because they watched a model emit it a thousand times.

The third case is slopsquatting, and it is the only supply-chain attack in history where the attacker's target list is generated for them, for free, by the victims' own tooling.

The same failure mode runs well past package names. Agents cite API endpoints that were never shipped, CLI flags that never existed, methods that were removed two majors ago, and legal citations with correct formatting and no underlying case.

The common structure: the agent is acting on recall, and there is no verification step between recall and action.

HALLUX is that step.

2. What HALLUX is, and what makes it hard to copy

HALLUX is a negative dataset. It records what does not exist.

Every registry on earth publishes what it contains. None publishes what it doesn't, because absence is unbounded. The useful subset of absence, the names models actually emit, can only be produced by adversarially sampling production models over time and confirming non-existence against an authoritative source. That corpus cannot be scraped. It can only be accumulated, and it compounds: every new model release adds its own hallucination fingerprint, and every day of history makes the phantom-to-squat transition data more valuable.

This is the defensible asset. The API is the delivery mechanism.

3. Verdicts

Every identifier resolves to exactly one verdict.

VerdictMeaningAgent action
existsPresent in the authoritative registry now.Proceed.
deprecatedExists but is retired, yanked, or superseded.Proceed with the replacement in successor.
absentNot present. No record of model emission.Do not proceed. Likely a typo or a private name.
phantomNot present, and emitted by production models at or above the attestation threshold.Do not proceed. This is a hallucination with a track record.
squatWas phantom, and has since been registered.Do not install. Treat as hostile until proven otherwise.
unknownNamespace supported but registry unreachable, or identifier outside coverage.Fail open or closed per your own policy. Do not treat as exists.

squat is the signal nobody else sells. A name that models invent, that a stranger then registers, is a supply-chain attack caught before the first install. The transition timestamp is in the response.

4. Namespaces

NamespaceCoversAuthority
pkg.npmnpm package namesregistry.npmjs.org
pkg.pypiPyPI distributionspypi.org
pkg.cratescrates.io cratescrates.io
pkg.goGo module pathsproxy.golang.org
pkg.mavenMaven coordinatessearch.maven.org
pkg.nugetNuGet packagesapi.nuget.org
api.endpointHTTP routes on known vendor APIsvendor OpenAPI documents
cli.flagCommand-line flags on common toolsshipped man pages, --help output
code.symbolFunctions, classes, methods in indexed librariesparsed source at version
cite.doiDOIsdoi.org
cite.legalUS case and statute citationsCourtListener, govinfo
model.idModel identifiers and API model stringsvendor documentation

Namespaces are additive. Unsupported namespaces return unknown with reason: "namespace_unsupported" rather than an error, so an agent's control flow never breaks on a HALLUX upgrade.

5. API

POST /v1/check

Batch up to 100 identifiers per request.

{
  "identifiers": [
    { "namespace": "pkg.pypi", "value": "requests-oauth2-helper" },
    { "namespace": "pkg.npm",  "value": "react-dom" },
    { "namespace": "pkg.npm",  "value": "openai-node-sdk" }
  ],
  "receipt": true
}

Response:

{
  "checkedAt": "2026-09-20T14:22:08Z",
  "results": [
    {
      "namespace": "pkg.pypi",
      "value": "requests-oauth2-helper",
      "verdict": "phantom",
      "confidence": 0.97,
      "evidence": {
        "registryCheckedAt": "2026-09-20T14:22:08Z",
        "registryStatus": "not_found",
        "attestations": 412,
        "firstObserved": "2025-11-04",
        "lastObserved": "2026-09-19",
        "observedFrom": ["gpt-class", "claude-class", "llama-class"],
        "nearestExisting": ["requests-oauthlib"]
      },
      "recommendation": "do_not_install",
      "successor": "requests-oauthlib"
    },
    {
      "namespace": "pkg.npm",
      "value": "react-dom",
      "verdict": "exists",
      "confidence": 1.0,
      "evidence": {
        "registryCheckedAt": "2026-09-20T14:22:08Z",
        "registryStatus": "found"
      }
    },
    {
      "namespace": "pkg.npm",
      "value": "openai-node-sdk",
      "verdict": "squat",
      "confidence": 0.99,
      "evidence": {
        "registryCheckedAt": "2026-09-20T14:22:08Z",
        "registryStatus": "found",
        "phantomSince": "2026-01-18",
        "registeredAt": "2026-06-02",
        "attestationsBeforeRegistration": 1188,
        "publisherAccountAge": "P14D",
        "publisherPriorPackages": 0
      },
      "recommendation": "block",
      "successor": "openai"
    }
  ],
  "receipt": {
    "alg": "Ed25519",
    "keyId": "blvkware-attestation-2026",
    "signature": "..."
  }
}

GET /v1/check/{namespace}/{value}

Single lookup. Free tier, no auth, no receipt. This exists so the cost of trying HALLUX is one curl command.

curl https://api.blvkware.dev/hallux/v1/check/pkg.pypi/requests-oauth2-helper

POST /v1/watch

Register identifiers for notification on verdict transition. The transition that matters is phantomsquat. Delivered by webhook.

GET /v1/corpus

Streaming JSONL of the phantom ledger. Rolling 30-day window free with attribution. Full history and live feed under commercial license.

MCP

The same capability is exposed as MCP tools at https://api.blvkware.dev/hallux/mcp, over Streamable HTTP, with no account and no key: hallux_check_command for an install command before it runs, hallux_check_manifest for a dependency file after it is edited, hallux_check for identifiers, and hallux_watch. Tool descriptions are written so a host model calls them unprompted before install and import operations. The same tools ship over stdio as hallux-mcp, for a host that prefers a local process.

6. Corpus methodology

Credibility here is the product, so the method is public.

  1. Elicitation. A panel of production models is prompted daily with realistic development, research, and citation tasks designed to induce identifier emission. Prompts are drawn from a rotating bank derived from real task shapes, not from adversarial jailbreaks.
  2. Extraction. Identifiers are parsed from output by namespace-specific grammars.
  3. Confirmation of absence. Each candidate is checked against the authoritative registry. Absence must be confirmed on two separate checks at least 24 hours apart before a candidate is eligible.
  4. Attestation. Each confirmed absence records the model family, the date, and the prompt class. One attestation is one model, one prompt class, one day. The same model emitting the same name twenty times against the same prompt in one run is one attestation, not twenty. An identifier becomes phantom at 10 attestations from at least 2 distinct model families.

The unit matters as much as the threshold. Counted per emission rather than per model-day, a sampler that runs one prompt twenty times promotes a name on its own, and "10 attestations" stops meaning what a reader assumes it means. Counted this way, ten attestations is a name that recurred across the panel and across days. The rule is enforced by a uniqueness constraint in the ledger, not by the discipline of whatever writes to it, so an ingest path cannot bypass it.

  1. Transition monitoring. Every phantom is re-checked against its registry daily, forever. Registration flips the verdict to squat and fires every registered watch.
  2. Decay. Phantoms with no attestation in 180 days are archived, not deleted. Archived entries still answer, with a staleness flag.

No model output is stored beyond the extracted identifier and its metadata. No prompts containing user data are used.

7. Receipts

Paid responses carry an Ed25519 signature over the canonical JSON of checkedAt and results. The public key lives at https://blvkware.dev/.well-known/blvkware-attestation.pub.

A receipt lets an operator prove, after an incident, that the agent checked and what it was told. That turns HALLUX from a convenience into an audit artifact, which is the form enterprises and insurers will eventually require.

8. Pricing

The constraint

HALLUX is never paid more because it blocked you.

The obvious model here is to charge per stop verdict: you pay when we save you. It aligns with value, it tracks cost almost exactly, and it makes a beautiful invoice line.

It is also disqualifying. A verification vendor paid per positive finding has the same structural flaw as a scanner paid per vulnerability: every marginal block is revenue, so the corpus has a commercial reason to grow, and no customer can ever fully rule out that the reason they were stopped was the invoice. This product is an argument about trustworthy verification. Being paid per block loses that argument before it starts.

So billing is a function of questions asked, never of answers given. This is enforced in code rather than promised: the quoting function accepts a count of identifiers and has no parameter through which a verdict could reach it, and a test asserts that the charge for a batch is identical whatever the batch resolves to.

The same rule governs watches. They are priced on what a customer chose to watch, never on whether it fired.

The ladder

TierWho buys itWhat it isPrice
OpenAny agent or developer, no accountSingle-lookup GET, 500 identifiers/day, every verdict, no receiptFree
MeteredAn individual agent or small teamBatch, receipts, watches. Capped, see below$0.0008 per identifier
TeamA company putting HALLUX in CIUnmetered, 100 watches, private-namespace exclusions$299/month, $2,990/year
FeedRegistries, IDE vendors, CI platforms, security vendors, insurersFull ledger, complete history, per-model attribution, live transition stream, unlimited watches, licence to surface findings in your product$1,500/month, $15,000/year
EmbeddedA platform shipping HALLUX inside its productSelf-hosted or white-labelled, BSL 1.1 commercial grantFrom $2,500/month

Watches on Metered are $0.02 per watched identifier per month.

An annual commitment is twelve months charged as ten.

Why these numbers

Open is the advertisement. 500/day unauthenticated is generous on purpose and will be abused. Rate limit by client at the edge and accept the loss, but bound it: all open-tier traffic shares one daily pool (50,000 identifiers), so a caller who can disguise their address can use up the free tier for the day but never make it bigger. The cost of trying HALLUX has to stay one curl command.

Metered is priced so that verification is never the reason not to verify. Resolving a forty-package dependency list costs about three cents, less than the model call that produced the list.

Metered is capped at the Team price. A pure per-identifier meter punishes the best channel: a CI pipeline asks about react and lodash a thousand times a day, those are cache hits that cost nothing to serve, and an invoice dominated by them reads as a tax on doing the right thing. Above 373,750 identifiers in a calendar month the account moves to Team and stops being metered. Volume becomes a subscription rather than a surprise. The cap is derived from the Team price in code, not typed, so the two cannot drift.

Team exists because metered billing is close to unbuyable in a company. It has no predictable number, so it has no purchase order, so it needs an exception. The draft ladder went straight from free to metered-forever and left the adopter we most want with nothing to buy. $299 sits under the line where an engineering manager needs approval, and adoption in CI is worth more than the margin above it.

Feed is the business. The per-call revenue will not pay the bills; it is the distribution channel. The feed and embedded tiers are bought by registries, IDE vendors, CI platforms, security vendors and insurers rather than by agents.

The earlier draft put Feed at $400/month. That was not caution, it was a credibility problem: a security vendor evaluating a threat-intelligence feed reads $400 as "no company behind this, no SLA, gone within a year" and stops reading. $1,500 is the low end of where differentiated feeds are actually priced, and still inside a data budget that one person can approve.

Feed should go up, on evidence, not on ambition. Two events justify raising it: publishing the first confirmed phantomsquat catch, and the corpus carrying a year of history. The asset is the accumulation. Do not raise the price before that evidence exists.

Settlement

x402 on Base and Solana for per-call, Stripe MPP for fiat session billing. Both rails on every paid endpoint.

9. Failure posture

HALLUX never returns exists on uncertainty. When the upstream registry is unreachable, the verdict is unknown with a reason code. An agent that treats unknown as permission has made that choice itself, and the receipt records it.

One carve-out, in the safe direction. An identifier that has already met the phantom threshold stays phantom when its registry is unreachable. It does not degrade to unknown. Both are stop verdicts, so this cannot open a door that was closed; the evidence carries registryStatus: "unreachable" and confidence is reduced, so nothing is concealed. The alternative is worse in two ways: it downgrades a name we have independently confirmed absent to "we do not know" on the strength of one failed request, and it hands anyone who can cause a registry timeout a way to launder a phantom into unknown, which, for a caller whose policy fails open, is a way to launder it into permission. Degradation is only safe when it degrades toward caution.

The same carve-out applies to squat, for the same reason and more strongly: registration is a recorded historical fact and does not stop being true because a registry stopped answering.

Latency budget: p95 under 120ms for cached identifiers, under 400ms for a cold registry round trip. A verification step that costs more than the action it guards will not be called.

Budgets are published as measurements, not as targets. /v1/proof computes them from the live call log, per namespace, because a blended figure hides the outlier that actually hurts: an uncached Go module path costs a fetch from the forge before the proxy will answer at all.

10. Build order

  1. Fold the existing pkgguard detection logic in as pkg.npm, pkg.pypi, pkg.crates.
  2. Stand up GET /v1/check/{namespace}/{value} with no auth. Instrument every call.
  3. Run the elicitation loop daily and publish the phantom counter publicly on the site. The counter is the marketing.
  4. Add POST /v1/check, receipts, and x402.
  5. Add transition monitoring and squat. Publish the first confirmed catch as a write-up. That single post is the credibility event the whole business rests on.
  6. Add api.endpoint and code.symbol. Those namespaces are where IDE vendors start caring.