Community

Apps

NostrDVM

This is not a normal client and not a wallet. NostrDVM is builder infrastructure for paid or free compute services that speak NIP-90, announce themselves with NIP-89 metadata and can wire Lightning, LNbits, zaps, Cashu edges and backend APIs into Nostr job events.

NostrDVM visual
NostrDVM icon
Apps The product layer Clients, signers, publishing tools, wallets and useful experiments.
Back to Nostr
Apps

Apps shelf

Apps pages collect clients, signers, tools, developer libraries and product research without turning the app into the whole network.

Apps28 min readPython framework for building and running NIP-90 Data Vending Machines on Nostr

NostrDVM

This is not a normal client and not a wallet. NostrDVM is builder infrastructure for paid or free compute services that speak NIP-90, announce themselves with NIP-89 metadata and can wire Lightning, LNbits, zaps, Cashu edges and backend APIs into Nostr job events.

The quick readNostrDVM is a Python framework by Believethehype for building and running NIP-90 Data Vending Machines. A DVM is a service provider that listens for Nostr job request events, decides whether the task is supported, may ask for payment, processes the input, and publishes a result event. The GitHub repository is MIT licensed, not archived, and its latest GitHub and PyPI version checked on June 14, 2026 was 1.1.3, published in August 2025. The package is still marked alpha on PyPI, and the README says the project is under development and interfaces may break. The important caution is wider than the package: NIP-90 itself is currently marked draft, optional and unrecommended in the official NIPs repository, with a warning that more specific microstandards may be preferable. That does not make NostrDVM useless. It makes it a serious experimental framework. If you use it, verify event kinds, NIP-89 announcements, relay behavior, payment-required feedback, LNbits credentials, NWC or Lightning permissions, API keys, task sandboxing, media downloads, database state and refund behavior before you let real users or real money depend on it.

Start with the exact object

NostrDVM is a framework, not a consumer app. You do not open it to read a timeline, chat with friends or manage a wallet. You use it when you want to run a Nostr service provider that accepts jobs, does work and returns the result as Nostr events.

The name expands around Data Vending Machines, the NIP-90 idea for services that receive a request from a customer and vend data back through the network. In practice that can mean summarization, translation, media conversion, image generation, discovery, search, text extraction, user lookup, MCP-like tasks or any other job type that can be expressed as an event.

The repository describes NostrDVM as a framework to build and run NIP-90 DVMs in Python. PyPI describes the same package as a framework for Nostr NIP-90 Data Vending Machines. The current public package version checked here is 1.1.3, and the package is still classified as alpha.

That alpha label matters. This is infrastructure for builders who can read code, inspect event shapes, limit payment risk and run staging tests. It is not a turnkey business service you should plug into a public product without understanding what the bot will sign, what relays it will trust and what external services the task code will call.

The protocol is useful but unsettled

NIP-90 is the standard reference behind the DVM pattern. It reserves job request kinds in the 5000 to 5999 range, job result kinds in the 6000 to 6999 range and feedback events at kind 7000. The broad rule is simple: a customer publishes a request, a service provider processes it, and the result kind is normally the request kind plus 1000.

The same NIP defines request tags such as input, output, bid, parameters, relays and provider pubkeys. It also defines feedback statuses such as payment-required, processing, error, success and partial. That gives clients enough vocabulary to ask for work, track progress and show a result.

The caution is in the current NIP text itself. The official repository marks NIP-90 as draft, optional and unrecommended, with a warning that the broad design became hard to control and that use-case-specific microstandards may be better. If you are building on NostrDVM, that warning should be part of your product plan.

So the right stance is neither hype nor dismissal. The DVM pattern is concrete enough to run working services today, and NostrDVM gives you real code for doing that. But the event vocabulary, task conventions, discovery layer and user expectations are still young. Build like you may need to migrate.

The project state

The main repository is `believethehype/nostrdvm` on GitHub. The repository metadata checked on June 14, 2026 showed a Python project, MIT license, not archived, with activity through 2025 and a latest release tagged 1.1.3 on August 13, 2025. PyPI also listed 1.1.3 and pointed back to the same GitHub homepage.

The README is direct about the development state. It says the project is under development, is in alpha and that interfaces might change or break. That is the kind of warning you should take literally when your DVM will handle wallet-related state, API keys, paid jobs or public announcements.

The package pins a number of dependencies that tell you what kind of workload the framework expects. It depends on `nostr-sdk`, media and scraping tools such as `yt-dlp`, `ffmpegio`, `moviepy`, `Pillow`, data packages such as `pandas`, `networkx` and `scipy`, and request and parsing libraries such as `requests` and Beautiful Soup.

Those dependencies are not bad by themselves. They are a signal that DVM jobs may fetch remote media, parse content, transform files, call model APIs and handle untrusted inputs. You should review both the framework and the specific task components you enable, because the task code is where most real operational risk lives.

How a job moves

The core flow is event driven. A NostrDVM instance starts a Nostr client, connects to configured relays, subscribes to job request kinds and watches for events addressed to its service. When a matching event arrives, the framework checks whether the configured task supports the input and whether the job should run.

If the event targets another provider with a `p` tag, the DVM can skip it. If the input references another unfinished job, the framework has code to wait instead of treating the missing result as ordinary input. If tags are encrypted, the code has paths for decrypting private task data before handing it to the task interface.

When the DVM works on a request, it creates a task-specific request object, calls the task's `process` logic and then posts a result event. The result kind follows the NIP-90 convention of request kind plus 1000. Feedback events can tell the user that the job is processing, requires payment, succeeded or failed.

That may sound like a normal job queue, but it is more public and more distributed. Relays carry the request, feedback and result events. Clients may only see some relays. Payment prompts can arrive as public feedback. Results may expire. Service reputation is tied to Nostr pubkeys and announcements, not to a single central dashboard.

What the framework gives you

NostrDVM gives builders a structure for writing tasks without rebuilding the relay loop every time. The `DVMFramework` can hold multiple DVM tasks, start them and keep them running. The task interface gives you hooks for initialization, input support checks, request parsing, processing, post-processing and scheduled work.

That task interface is the important developer contract. A simple DVM can define what kind it handles, how to turn a Nostr request event into internal data, and what result to return. The example in `main.py` creates a generic DVM around kind 5050 and publishes NIP-89 metadata for discovery.

The framework also includes definitions for many job families. The code includes kinds for text extraction, summarization, translation, text generation, image generation, video conversion, video generation, text to speech, content discovery, people discovery, content search, user search, MCP-style jobs, subscriptions and generic DVM work.

You should still treat those as implementation affordances, not final product guarantees. A kind definition tells you what category the framework can express. It does not prove a particular service is reliable, priced fairly, fast, safe, private or compatible with every client that claims DVM support.

NIP-89 is the shop window

A DVM needs discovery. If no client can find the service, the job engine can be perfect and still receive no work. NostrDVM uses NIP-89 style announcements to publish service metadata with kind 31990. Those announcements can include supported job kinds, descriptions, names, images, payment notes and task parameters.

NIP-89 was originally framed as a way to recommend application handlers for event kinds that clients may not understand. DVMs reuse the same practical idea: announce that a provider can handle certain event kinds, then let clients discover possible service providers instead of hardcoding every pubkey.

The framework's NIP-89 utilities can create and delete announcements. The DVM config has relay lists for announcing services, and the example metadata can include fields such as supported encryption, NutZap support and `nip90Params`. That is useful because clients need more than a name; they need to know what a service claims to accept.

Announcement metadata is still not trust. A bad provider can announce attractive capabilities. A stale provider can keep old metadata on relays. A client can query too broadly and pick up spam. NIP-89 gives discoverability, not reputation, uptime, price history or code audit.

The cold start problem is real

The open issue titled `DVM Discovery: Cold Start Problem - NIP-89 Dynamic Discovery Not Implemented in Clients` is worth reading before you build a business around this pattern. The report says a compliant NIP-89 DVM announcement was published to multiple relays, but the operator saw zero requests over more than 72 hours.

The issue's diagnosis is blunt: several popular clients did not dynamically discover DVMs through NIP-89. They used known or hardcoded handlers instead. That means a technically correct service can still be invisible to ordinary users if the client ecosystem does not surface it.

This is not only a NostrDVM problem. Any DVM framework faces the same market structure. Providers need clients. Clients need trustworthy provider lists. Users need understandable prompts. Relays need to carry the right announcements. Payment UX needs to be clear enough that people do not feel tricked by invisible service calls.

For you as a builder, the action is practical. Do not assume publishing a kind 31990 announcement is distribution. Test the exact clients you expect users to use. Document the provider pubkey. Provide a direct client integration path. Watch whether requests arrive. Treat discovery as a product feature, not a background protocol detail.

Payments can be free, paid or mixed

NIP-90 allows free and paid work. NostrDVM reflects that. A task can run freely, be whitelisted, ask for payment with a feedback event, use a BOLT11 invoice, receive zaps, work with Cashu/NutZap paths or tie into subscription-style logic. That flexibility is powerful, but it is also where many user mistakes happen.

The DVM code can send a payment-required feedback event with an amount tag and an optional invoice. It also watches for zap events and NutZap-related events, checks whether a paid job has enough payment, and resumes or starts work when payment arrives. Failed paid work can trigger error feedback and, in some cases, refund-like zapback attempts.

A user should always be able to tell whether a task is free, prepaid, pay-on-result, subscription based or experimental. A builder should be able to tell which event caused the charge, which invoice was paid, which result was delivered and what happens when processing fails after payment.

Do not hide this behind cheerful automation. Paid compute over Nostr can be elegant, but the wallet prompt is where trust either survives or breaks. Small amounts, explicit status events, clear provider identity and conservative wallet permissions matter more than a clever demo.

LNbits is a sensitive dependency

The README explains that if you want the framework to manage wallets or Lightning addresses automatically, you can create an LNbits account on an accessible instance and provide an account ID, wallet ID, admin key and host. If you do not want that path, you can leave the LNbits fields empty and make each DVM free or give it a manual Lightning address.

That setup is convenient because it can create invoices, manage payment state and help make DVM profiles zappable. It is also sensitive. An LNbits admin key is not a decorative config value. Depending on the wallet and instance, it may be able to create wallets, pay invoices or inspect payment state.

The `.env_example` also shows other secrets that may be needed by task backends: OpenAI, LibreTranslate, Replicate, Hugging Face, CoinStats and Nostr.build credentials, among others. A DVM process can become a collection point for wallet keys, model API keys, file-upload credentials and service tokens.

Treat the environment file as production infrastructure. Keep it out of Git. Back it up securely if it controls wallet access. Rotate keys after experiments. Use separate wallets and API keys for staging. Do not run unknown task components with a production LNbits admin key in the same environment.

Encryption helps but does not remove trust

DVM requests can include public inputs and private inputs. NIP-90 describes encryption for private task data, and the NostrDVM code has paths for decrypting encrypted tags and for replying with encrypted output. The codebase references both older NIP-04 style encryption paths and newer NIP-44 style handling in related DVM client ecosystems.

Encryption protects against casual relay visibility, but the service provider still receives the task content after decryption. If you ask a summarizer to process a private document, the DVM operator and the backend APIs it calls may see that document. If you ask an image model to process media, the task may download or upload the media elsewhere.

That means private inputs need a threat model. Which DVM pubkey can decrypt them? Does the task call OpenAI, Replicate, Hugging Face, LibreTranslate or another external provider? Is the result encrypted back to the requester? Are logs scrubbed? Can failed jobs leave decrypted data in temporary files?

For sensitive work, do not treat Nostr encryption as a complete privacy guarantee. It is one layer in a workflow that may include relays, a Python process, a database, temporary media files, third-party AI APIs and payment metadata. The whole chain matters.

Relay choices shape reliability

NostrDVM ships with default relay lists in its configuration utilities. The defaults include relays such as `wss://relay.nostrdvm.com` and `wss://nostr.oxtr.dev`, while announcement and database sync paths reference other common relays such as Primal and Damus relays. Those defaults are useful for testing, not a complete availability plan.

A DVM relies on relays for request discovery, feedback delivery, result publication, zap receipts, announcements and sometimes heartbeat-like visibility. If the requester and provider do not share relays, a job may never be seen. If a result is published only to relays the client does not read, the user may think the job failed.

The framework can tag result events with relays and expiration information. It can also track unfinished jobs and poll for payments. But a distributed relay environment still has ordinary failure modes: relay downtime, auth policy, rate limits, spam filtering, paid relay requirements, slow subscriptions and conflicting views of event history.

Before production, test with the relays your users actually use. Publish a request from a real client, watch the provider receive it, watch the feedback event, pay if required, then fetch the result from another client. A green local log is not enough if the network path is invisible to users.

Task code is the product

The framework is the vending-machine chassis. The task code is what people actually buy or use. NostrDVM includes task examples for text extraction, translation, summarization, image generation, media conversion, search and discovery. Each task can have different dependencies, external APIs, content rules and failure modes.

Media tasks deserve special caution. Packages such as `yt-dlp`, `ffmpegio`, `moviepy` and Pillow suggest workloads that may fetch remote media, parse files, transcode video, inspect images or generate output files. That is exactly the kind of work where untrusted input, oversized files and malicious media can hurt a server.

AI tasks have another set of risks. Prompt content may be sent to a model provider. Model responses may be wrong, unsafe or copyrighted. API costs can spike. Rate limits can break jobs after payment. A task may need to store intermediate files or logs to debug failures, which can create privacy risk.

Do not evaluate NostrDVM only by whether the framework starts. Evaluate each task as a separate service. Give it resource limits, input validation, timeout behavior, temporary storage cleanup, API spend caps, logs that avoid secrets and a clear user message when a job cannot be completed.

Cashu and subscriptions are advanced edges

The codebase includes support paths around NutZap events, Cashu wallet announcements and NIP-88 style subscription concepts. These are interesting because they point toward richer DVM business models: paid tasks, prepaid balances, subscription tiers, ecash-like receipts and service-specific access.

They are also advanced edges. Cashu mints, proofs, wallets and melt flows introduce their own trust and failure models. Subscriptions introduce recurring entitlement checks and renewal logic. Splits and zapbacks can create accounting questions. A DVM that handles simple free text generation is not the same risk profile as one that manages paid tier access.

If you enable these features, test them separately from basic job processing. Confirm wallet announcement events, mint choice, proof redemption, subscription tier events, entitlement checks, payment expiry, duplicate payment handling, failure refunds and what happens when a mint or relay becomes unavailable.

For many builders, the right first version is simpler: free tasks or tiny one-off payments, no subscriptions, no broad wallet authority and no multi-mint complexity. Once the service proves useful, you can add more payment machinery with evidence instead of hope.

What a client must show

A DVM client should not make users guess what is happening. It should show the provider identity, the job kind, the input summary, whether the request is encrypted, the expected price, the payment method, the status event, the result event and a way to inspect or copy raw event data when needed.

NostrDVM can publish the provider side of that story, but the user experience also depends on clients. A provider can send good feedback events and still look broken in a client that hides feedback. A provider can publish NIP-89 metadata and still be invisible in a client that does not query announcements.

That is why DVM builders should test with real user surfaces, not only with scripts. Use a client or demo page that shows payment-required status. Check whether the result is attributed to the right provider. Check whether a failed job looks like an error, a timeout or a missing event.

If you are building both the provider and the client, resist the urge to hide every protocol detail. Normal users do not need raw JSON first, but they do need enough provenance to trust a paid result. Provider name, pubkey, price, status and source event links are the minimum healthy surface.

Operational risks before public use

Running a DVM is closer to running a public worker service than running a static website. The process holds signing keys, connects to relays, may hold wallet or LNbits credentials, may call paid APIs, may download user-supplied content and may publish public results that users expect to find later.

The default config generator can create or check private keys and LNbits-related settings. That is helpful in development, but production needs a key policy. Know where the DVM private key lives, how it is backed up, how it can be rotated, which profile or NIP-89 announcement it controls and what damage a compromised key can do.

You also need resource controls. Jobs should have timeouts. Media downloads should have size limits. API keys should have budgets. Temporary files should be cleaned. Logs should avoid secrets and private inputs. Relays should not be allowed to push unlimited workload into a server with no queue discipline.

Finally, write a failure story. If the DVM takes payment and then crashes, what event does the user see? If the result is wrong, can the user report it? If the model provider is down, is the invoice withheld, refunded or marked failed? These boring questions become the product the first time a user loses sats.

How to test it

Start with a local or staging DVM and one harmless task. Use a fresh keypair, a small relay set and no payment. Publish a request event of the expected kind, confirm the DVM sees it, confirm the task supports the input, and confirm the result appears with the correct result kind and request reference.

Then test discovery. Publish the NIP-89 announcement, fetch it from the same relays with an independent client, and verify the kind tags, name, description, provider pubkey, supported parameters and any payment metadata. Do not move on until another tool can see what your service claims to offer.

After that, add payment in the smallest possible form. Use a test wallet or tiny LNbits wallet, set a tight budget, request a paid task, inspect the payment-required feedback, pay the invoice, and confirm the DVM resumes the exact job rather than starting a duplicate. Leave one invoice unpaid and confirm it expires cleanly.

Only then test hostile edges: invalid tags, unsupported input, too-large media, unreachable URLs, backend API timeout, relay disconnect, duplicate events, wrong payment amount, server restart during processing and a rotated key. A DVM that survives those cases is much closer to something a reader can trust.

Who it fits

NostrDVM fits builders who want to experiment with Nostr-native service providers. If you are building search, summarization, translation, media conversion, AI generation, paid data lookup or discovery services, it gives you a working Python framework for relay subscriptions, event handling, announcements and payment-related status flows.

It also fits researchers who want to understand the DVM category by reading running code. The official NIP explains the vocabulary. NostrDVM shows how a real service tries to turn that vocabulary into tasks, queues, relays, keys, invoices, zaps and result events.

It does not fit users who only want a wallet connection, a simple client or a polished app store experience. It also may not fit teams that require a frozen standard, formal security audit, enterprise support or guaranteed compatibility across mainstream clients today.

The best user is a careful builder with staging discipline: someone comfortable reading Python, inspecting Nostr events, limiting wallet permissions, checking relay behavior and treating alpha framework warnings as engineering constraints rather than footnotes.

The practical close

NostrDVM matters because it turns the DVM idea from a protocol sketch into code a builder can run. It can listen for Nostr jobs, announce service capabilities, process task inputs, publish results, ask for payment and connect Lightning or ecash-adjacent flows to compute work.

Its limits are just as important. NIP-90 is currently flagged with a warning. Discovery is not solved across clients. The package is alpha. Payment flows can hold sensitive keys. Task code can call expensive or risky services. Relays can make a working job invisible.

Use NostrDVM as a serious experiment, not as invisible plumbing you never audit. Read the code, run one task, inspect the events, prove discovery, keep payments tiny, protect LNbits and API secrets, and document exactly which relays and clients your service supports.

If that sounds like work, it is. But it is the right kind of work for this layer of Nostr: a public service marketplace will only become trustworthy if builders make the jobs, payments, keys and failure states visible before users have to learn them the hard way.

Useful Nostr context

These pages help readers place DVM tooling beside the protocol pages and commerce surfaces that use data vending.

Sources worth opening

Open the repository and PyPI package first, then compare NIP-90, NIP-89, the framework internals, payment utilities, LNbits setup notes and the discovery issue that describes why DVM adoption still has rough edges.

Back to the Crays Nostr page
Apps route visual cue 1
Apps route visual cue 2
Apps route visual cue 3
Apps route visual cue 4
Apps route visual cue 5

How to use this page

Keep the product map close.

Search the wider app shelf when you want another client, tool, protocol reference or source trail beside this page.

AppsBrowse Apps pagesApps pages stay availableProducts, tools, communities and source trails.Browse pages
Apps contribution visual cue 1
Apps contribution visual cue 2
Apps contribution visual cue 3
Apps contribution visual cue 4
Apps contribution visual cue 5

Bring something back

Ask, suggest, submit or nominate.

Ask a question, send a source, suggest a fix, submit a project or nominate a public Nostr account. The page stays stable; your contribution gets reviewed beside it.