Native Shell
Native Shell: AI-generated UI, native in your app, on every platform. Apps on iOS, Android, macOS, Windows and Linux, GPUI apps and web pages load signed, sandboxed TSX modules at run time and draw th
Decentralized GPU compute for inference and training. Operators earn crypto for the GPUs they already have; clients pay in any supported coin.
Developer toolsJavaScript · HTMLGitHub @InfernetProtocolOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Infernet: A Peer-to-Peer Distributed GPU Inference Protocol
Translation pending
Taken from the repository README
Loading the full README.
Read the full README ↗A decentralized GPU compute marketplace for inference and distributed training, running as a workload plugin on top of c0mpute. Rent a GPU anywhere, install c0mpute, add the infernet plugin, start earning crypto. The control plane is a Next.js dashboard; GPU nodes authenticate with Nostr-signed HTTP requests — they never hold a database credential, run as an unprivileged user, and can operate outbound-only. Scales horizontally — every new provider on the network is real, additional capacity.
Infernet runs on c0mpute. The peer discovery + auction substrate (libp2p Kad-DHT + gossipsub) lives in c0mpute, shared with other workload plugins (transcode, etc.). Infernet contributes the AI-specific layer: federated inference (llama.cpp RPC), the chat / completions API, the routing logic, and the Nostr-keyed identity model.
What we are, what we aren't. Infernet is the economic substrate for inference jobs that don't need NVLink — single-GPU inference (7B–70B), embarrassingly parallel batch (embeddings, image grids, sweeps), LoRA fine-tunes, and async / federated distributed training (DiLoCo-style). We don't try to match hyperscalers on tight-sync 100B+ training from scratch — that workload's interconnect moat is real and conceding it costs us nothing. The dominant inference market is request-level parallel, where per-job latency is dominated by GPU compute, not network hops. As inference ASICs (Apple Neural Engine, Qualcomm Hexagon, Tenstorrent, Groq, Cerebras, AWS Trainium) commoditize the silicon, the protocol layer is what stays valuable. Bitcoin's real lesson: the protocol survived three hardware generations because it didn't depend on any of them.
Canonical links:
Two lines on Linux, macOS, or Windows (WSL2):
# 1. Install c0mpute (the p2p substrate; brings in mise, bun, ffmpeg)
curl -fsSL https://c0mpute.com/install.sh | sh
# 2. Add the infernet plugin (installs the infernet CLI + daemon)
c0mpute plugin install infernet
The first command sets up c0mpute itself — peer discovery, the
gossipsub auction layer, capability registry, and the toolchain
(mise + bun) that plugins share. The second pulls
https://c0mpute.com/plugins/infernet/install.sh which lays down the
infernet CLI at ~/.local/bin/infernet and registers infernet as
the AI-inference workload type on the c0mpute network.
The CLI itself is POSIX shell, so Windows operators run it inside WSL2 and the daemon picks up the GPU through Microsoft's WSL CUDA driver path:
wsl --install -d Ubuntu from PowerShell, reboot.Outbound poll for chat + remote model commands works as-is. Direct
P2P inbound on :46337 requires a netsh interface portproxy rule on
the Windows host (skip it if you only care about earning via routed
jobs — the control plane handles that path outbound-only).
Then:
infernet setup # interactive: installs Ollama, pulls a model,
# opens the firewall (sudo), saves config
infernet chat "hi" # local inference, no control plane needed
infernet model list # see what's pulled
infernet tui # live dashboard (q to quit)
infernet help # full command list
| Method | Command | Status |
|---|---|---|
| c0mpute plugin (above) | c0mpute plugin install infernet | ✅ works today |
| Direct plugin URL | curl -fsSL https://c0mpute.com/plugins/infernet/install.sh | sh | ✅ works today (same script) |
| Docker | docker run --rm -it --gpus all ghcr.io/profullstack/infernet-provider:latest | ✅ works today |
| Manual git clone | git clone … && pnpm install && node apps/cli/index.js | ✅ works today |
| npm global | npm install -g @infernetprotocol/cli | 🚧 blocked on npm token regen |
| Homebrew | brew install infernet | 🚧 unblocks when npm does |
c0mpute plugin uninstall infernet # removes the infernet CLI + daemon
rm -rf ~/.config/infernet # also removes node identity + saved config
(Or, to remove c0mpute entirely: c0mpute uninstall --purge.)
/chat — streams tokens via Server-Sent Events. Uses live P2P providers if any are online; otherwise falls back to NVIDIA NIM (build.nvidia.com) so the demo never breaks./deploy — mint a 24h bearer, paste the one-liner into your provider's user-data field, the box auto-detects platform + volume + GPU, installs the right engines, registers, and starts heartbeating.INFERNET_RAY_MODE=head|worker env vars.@infernetprotocol/training package with backends for DeepSpeed (Class B), OpenRLHF (Ray + vLLM rollouts + DeepSpeed updates), OpenDiLoCo (Class C), Petals (Class B.5 fine-tunes), and stub. See IPIP-0011.POST /api/v1/jobs/batch splits one logical job (embed N docs, classify N items) into chunks fan-out across providers. BullMQ default queue, Postgres-queue fallback.infernet CLI — one binary per GPU server. Subcommands: init, login, register, update, remove, start, stop, status, stats, logs, payout, payments, gpu, firewall, chat, tui, model, setup, service, doctor. Daemon has a local IPC socket for live queries + a direct P2P chat transport on TCP 46337 (dual-stack IPv4/IPv6) for streaming inference between consumer and provider. (libp2p Kad-DHT + gossipsub) — infernet doesn't run its own DHT anymore.Design goals: a GPU node should be able to run as an unprivileged user, leak as little as possible about its host, and never hold a credential that could compromise the rest of the network.
/api/v1/node/* with a signed envelope on every request.X-Infernet-Auth: base64url({ v, pubkey, created_at, nonce, sig }) where sig is a Schnorr signature over METHOD + path + created_at + nonce + sha256(body). 60-second replay window, per-process nonce cache, pubkey must match public_key on the target row.{ vendor, vram_tier, model } per GPU. Hostname, platform, arch, CPU model, RAM total are discarded both client-side and at the server sanitizer.--no-advertise to init / register / start and the node never publishes an IP or port; it only pulls work via signed polls. Pairs naturally with Tor or a NAT.~/.config/infernet/config.json (mode 0600). No /etc, no /var, no sudo, no privileged ports (default P2P port 46337, override with --p2p-port).supabase.serviceRoleKey are stripped silently on load — the field never gets re-saved to disk.The control plane runs one of two ways:
supabase start). Best for privacy and offline development.https://infernetprotocol.com. Rent a GPU anywhere, infernet init, start earning.Operators can point many GPU nodes at the same control plane — each node has its own Nostr identity and shows up as its own row in the dashboard.
One block, zero ssh, no manual infernet setup afterwards. Mint a 24h
bearer at /deploy, then on the
target box:
curl -fsSL https://c0mpute.com/install.sh | sh
INFERNET_BEARER=$TOKEN INFERNET_MODEL=qwen2.5:7b \
c0mpute plugin install infernet
What it does: c0mpute's installer detects platform, installs mise +
bun + ffmpeg, lays down the c0mpute binary, and (by default) symlinks
the shard data dir onto the biggest writable volume. The plugin
installer then drops the infernet CLI, runs infernet init +
login --token + setup --yes + start so the node registers,
heartbeats, and starts taking jobs in one shot.
For RunPod / DigitalOcean / AWS / bare-metal cloud-init, paste both
lines into the platform's "user data" or "container start command"
field. Works in any Linux box with curl and root.
The control-plane-mediated chat path does not need inbound connectivity — the daemon polls and posts outbound. Port 46337 only matters if you want the direct P2P chat transport (consumer dials provider for low-latency streaming). Residential operators behind NAT can skip port forwarding and still earn.
┌────────────────────────────────────────────────┐
│ Next.js dashboard (self-hosted OR cloud) │
│ /chat · /deploy · /api/* · SSE streaming │
│ /api/v1/node/* — signature-verified endpoints│
└───────────────────────┬────────────────────────┘
│ (server-side only)
▼
┌────────────────────────────────────────────────┐
│ Supabase │
│ providers · clients · aggregators · jobs │
│ users · job_events · platform_wallets │
│ provider_payouts · payment_transactions │
└────────────────────────────────────────────────┘
▲
Nostr-signed HTTP │ anon / SSE
(BIP-340 Schnorr) │
┌────────────┐ ┌──────────┐ ┌─────────────────┐
│ infernet │… │ Expo app │ │ NVIDIA NIM │
│ CLI daemon │ │ │ │ (fallback only) │
│ P2P:46337 │ └──────────┘ └─────────────────┘
│ IPC sock │
└────────────┘
The GPU node holds a Nostr keypair (generated on infernet init); every
call to the control plane carries an X-Infernet-Auth envelope with a
Schnorr signature over method + path + timestamp + nonce + sha256(body).
The server enforces that the signing pubkey owns the target row. No DB
credential ever lives on the node.
Full detail: INFERNET-ARCHITECTURE.md.
@supabase/supabase-js)linux/amd64 + linux/arm64)Self-hosted:
pnpm install
pnpm supabase:start
pnpm supabase:db:reset # applies all migrations in supabase/migrations/
pnpm dev # dashboard at http://localhost:3000
Or point at Supabase cloud:
pnpm install
pnpm supabase:login
pnpm supabase:link
pnpm supabase:db:push # pushes migrations to the cloud project
pnpm dev
Copy sample.env → .env and fill in SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, and the CoinPayPortal keys.
docker run --rm -it \
--gpus all \
-p 46337:46337 \
-e INFERNET_CONTROL_PLANE_URL=https://infernetprotocol.com \
-e INFERNET_NODE_NAME=edge-01 \
ghcr.io/profullstack/infernet-provider:latest
Multi-arch (linux/amd64 + linux/arm64). The image calls infernet init → infernet register → infernet start --foreground internally, so one command boots a provider and starts accepting jobs. No database credentials are passed in — the container generates its own Nostr keypair on first run and uses it to sign every request.
If you cloned the repo:
pnpm install
pnpm --filter @infernetprotocol/cli start -- help # any subcommand
Full CLI surface: init, login, register, update, remove, start, stop, status, stats, logs, payout, payments, gpu, firewall. Config lives at ~/.config/infernet/config.json.
npm install (npm i -g @infernetprotocol/cli) and Homebrew (brew install infernet) are on the roadmap.
infernet init walks through:
https://infernetprotocol.com, or your self-hosted instance)provider / aggregator / client)--nostr-privkey)--no-advertise to stay outbound-only--address)nvidia-smi / rocm-smi / system_profilerConfig lives at ~/.config/infernet/config.json (mode 0600). It contains the node's Nostr keypair and the control-plane URL — no database credentials, no service-role keys.
Node lifecycle:
init First-time setup (generates Nostr keypair)
login Re-point at a different control plane
register Announce this node (signed POST /api/v1/node/register)
update Re-push current state (signed; upsert)
remove Deregister and wipe local config (signed)
Daemon:
start Start daemon (detached; --foreground for supervisors)
stop Stop daemon (graceful via IPC, signal fallback)
status Control-plane row + live daemon snapshot
stats Live in-memory daemon stats via IPC
logs Show / tail the daemon log (-f for follow)
Diagnostics:
gpu Inspect local GPUs (list | json)
firewall Print firewall commands for the P2P port
Payments:
payout Manage payout coin/address (set, list)
payments Show recent payment transactions
infernet start detaches into the background (logs at ~/.config/infernet/daemon.log) and exposes a Unix-domain IPC socket at ~/.config/infernet/daemon.sock. The other CLI commands use that socket for live queries:
infernet status fetches this node's row from the control plane (signed POST /api/v1/node/me) and merges it with the daemon's in-memory snapshot.infernet stats shows heartbeat counts, poll counts, active jobs, uptime, P2P connections.infernet stop sends a graceful shutdown command; falls back to SIGTERM via the PID file.infernet logs -f tails the log file.Use infernet start --foreground under systemd / Docker / Kubernetes when a supervisor wants the process in the foreground.
A node restarts itself; you should never have to notice it went down.
infernet setup installs a systemd user unit on Linux (with loginctl enable-linger, so it runs without a login and starts at boot) or a launchd agent on macOS. Opt out with --no-service or INFERNET_NO_SERVICE=1; containers rely on their own restart policy.infernet start runs a small built-in supervisor that restarts the daemon after a crash or kill (backoff 1 s doubling to 60 s). infernet stop stops the supervisor too.Every provider node pulls and serves Infernet's house models by default: the models listed in apps/web/public/house-models.json, served at https://infernetprotocol.com/house-models.json. Today that is Profullstack's hf.co/profullstack/saas-business-strategist-agent-GGUF and hf.co/profullstack/not-a-lawyer-agent-GGUF (legal research, not legal advice) and hf.co/profullstack/tax-guy-agent-GGUF (tax research, not tax advice) plus the uncensored huihui_ai/qwen3.5-abliterated:4b and :9b.
min_ram_gb, at least 10% of the disk left free afterwards (10-50 GB), and under the operator's disk cap if set.~/.config/infernet/house-models-state.json) are.infernet status and infernet house-models show what is pulled and the disk it uses; infernet house-models list shows the list and what fits here.infernet house-models off (or --no-house-models on install/setup/start, or INFERNET_HOUSE_MODELS=0). Uncensored ones only: infernet house-models uncensored off (--no-uncensored-models, INFERNET_UNCENSORED_MODELS=0). Disk cap: infernet house-models cap 20 (INFERNET_HOUSE_MODELS_MAX_GB).{name, source, digest, size_bytes, min_ram_gb, min_disk_gb, uncensored, license, description, added} to that file. digest is the sha256 of the registry manifest (what /api/tags reports after a pull); size_bytes is all layers plus config. Details: /docs/house-models.An aggregator verifies providers independently: every minute it dials each provider's advertised P2P address, checks it answers as the node it claims to be, and reports reachability and round-trip time (signed POST /api/v1/node/aggregator/probes). /status and each /nodes/<id> page show how many aggregators reached a provider in the last hour. Anyone can run one, on any small box:
infernet init --role aggregator --name my-aggregator
infernet register
infernet setup --yes # installs the service; or `infernet start`
Running it on a box that already runs a provider? Give it its own config dir and let only the provider update the install: XDG_CONFIG_HOME=/var/lib/infernet-aggregator INFERNET_AUTO_UPDATE=follow infernet start --foreground --no-p2p (and a free PORT for its /healthz). In follow mode a daemon never runs the installer; it restarts into a newer version once one is installed.
Coordinating multi-node jobs (IPIP-0028 / IPIP-0033) is the next aggregator duty.
Each provider/aggregator node binds TCP 46337 (dual-stack) for peer communication. Change with --p2p-port, or disable with --no-p2p. The node advertises its address:port to the control plane on every signed heartbeat so other nodes can discover it — unless it was started with --no-advertise, in which case nothing is published and the node operates outbound-only.
Need to open the port on your firewall? infernet firewall prints the exact commands for ufw / firewalld / nftables / iptables (Linux), pf (macOS), or netsh (Windows). We never touch firewall state automatically.
The CLI auto-detects GPUs on init, register, update, and daemon heartbeat:
nvidia-smi — model, VRAM, driver, CUDA version, utilization, temperature, power.rocm-smi — same fields where available.system_profiler — model, unified memory.Detected GPUs feed the coarse capability payload that lands in providers.specs.gpus (jsonb): { vendor, vram_tier, model } per card, plus gpu_count. Enough to route jobs (e.g. "find me a provider in the 24-48gb tier") without broadcasting the machine's full fingerprint.
When the P2P network has no live providers, the chat playground transparently falls back to build.nvidia.com's OpenAI-compatible endpoint so the UX never breaks while the network is bootstrapping. Controlled by three env vars (all optional; leave blank to disable):
NVIDIA_NIM_API_KEY= # from https://build.nvidia.com/
NVIDIA_NIM_API_URL=https://integrate.api.nvidia.com/v1
NVIDIA_NIM_DEFAULT_MODEL=meta/llama-3.3-70b-instruct
Same SSE contract as the P2P path — tokens are mirrored into job_events so the audit trail is identical. The chat UI badges fallback responses "NVIDIA NIM (fallback)" for transparency. Adapter: packages/nim-adapter.
Consumers can pay for jobs and providers can be paid out in any of these coin/network combinations:
BTC, BCH, ETH, SOL, POL, BNB, XRP, ADA, DOGE; plus USDT on ETH/Polygon/Solana; plus USDC on ETH/Polygon/Solana/Base.
packages/config/payment-coins.jspackages/config/deposit-addresses.js — also seeded into the platform_wallets table.packages/payments/src/coinpayportal.js). Set COINPAY_API_KEY, COINPAY_WEBHOOK_SECRET (and optionally COINPAY_BUSINESS_ID) in .env.GET /api/payments/methods lists every coin the CoinPay business takes, plus PayPal; hosted: true once CoinPay hosts checkout sessions.POST /api/payments/invoice with { jobId, method } (USDC_POL, BTC, paypal, ...) or { jobId, coin, network }; returns paymentUrl. Metadata carries property, account_id (the job's client) and email.POST /api/payments/webhook, verified by X-CoinPay-Signature; settles by the stored CoinPay id, updates payment_transactions + jobs.payment_status.Provider earnings flow into the outbound direction of payment_transactions. Configure a payout wallet with infernet payout set <COIN> <ADDRESS>.
Signed-in accounts hold a consumer compute-credit balance (credit_ledger, unit credits, from
@profullstack/redeem-credits). It is a
customer balance only: it is separate from provider earnings (provider_earnings / payout_requests), nothing
in the payout path reads it, and it can never be withdrawn.
CR-XXXX-XXXX-XXXX-XXXX, stored as sha256 only) are minted by an admin and redeemed on
/settings ("Have a code?"), with POST /api/v1/credits/redeem or infernet redeem <code>.
Mint: infernet credits admin mint --credits 500 --label "for X" (or POST /api/v1/admin/credit-codes
with Authorization: Bearer $INFERNET_ADMIN_TOKEN); list / revoke the same way.INV-XXXX-XXXX-XXXX, @profullstack/affiliates):
3 per account, single use, 30-day expiry, sendable once an account is 7 days old, accepted only by accounts up
to 7 days old, one per account. /invites lists them; /i/<code> is the landing link (the code is kept in a
cookie and in the signup's user_metadata, so the confirmation link counts from any browser). When the new
account has confirmed its email, both people get INFERNET_INVITE_BONUS_CREDITS (default 100) credits, unless
the two addresses are the same mailbox (+tags, Gmail dots), either uses a throwaway domain, or the inviter
already had 10 bonuses in 30 days. Each side is decided once (invite_bonuses)./?ref=<code> (shown on /invites); first touch is kept in the referral_code cookie and
recorded at sign-in.GET /api/v1/credits, POST /api/v1/credits/redeem, GET|POST /api/v1/invites,
DELETE /api/v1/invites/{id}, POST /api/v1/invites/accept; admin GET|POST /api/v1/admin/credit-codes,
DELETE /api/v1/admin/credit-codes/{id}. CLI: infernet credits|redeem|invites. MCP: credits_balance,
credits_redeem, invites_list, invite_create.apps/
web/ Next.js dashboard + /chat + /deploy + REST/SSE API
cli/ The `infernet` binary (commands + daemon + IPC)
desktop/ Electron shell wrapping the Next.js app
mobile/ React Native + Expo app
daemon/ Placeholder for future standalone service daemons
packages/
config/ Payment-coin list + canonical deposit addresses
auth/ Nostr identity + signed-request envelope (BIP-340)
db/ Supabase-backed model layer (server-side only)
gpu/ GPU detection (NVIDIA / AMD / Apple Silicon)
inference/ Distributed inference coordinator / worker
payments/ CoinPayPortal gateway
logger/ Structured logger
sdk-js/ @infernetprotocol/sdk — REST + SSE client
api-schema/ OpenAPI 3.1 spec for the control-plane API
deploy-providers/ Cloud-GPU deploy adapters (RunPod today)
nim-adapter/ NVIDIA NIM fallback inference adapter
tooling/
docker/provider/ Dockerfile + entrypoint for ghcr.io/.../infernet-provider
dist/homebrew/ Homebrew formula + release-time updater
supabase/migrations/ SQL schema (applied via supabase CLI)
tests/ Vitest suite
GET /api/overview
GET /api/nodes
GET /api/jobs
GET /api/providers
GET /api/aggregators
GET /api/clients
GET /api/models
POST /api/chat Chat playground — picks P2P provider OR NIM fallback, returns streamUrl
GET /api/chat/stream/[jobId] SSE: tokens streamed live (job|meta|token|done|error)
GET /api/payments/methods CoinPay coins + PayPal on offer
POST /api/payments/invoice CoinPay checkout for a job
POST /api/payments/webhook CoinPayPortal webhook sink (HMAC-verified)
GET /api/deploy/runpod/gpu-types RunPod GPU catalog (proxied via user API key; not stored)
POST /api/deploy/runpod One-click launch an Infernet provider pod
Signature-verified node API (Nostr / BIP-340 Schnorr):
POST /api/v1/node/register Upsert a provider/aggregator/client row
POST /api/v1/node/heartbeat Refresh last_seen / status / address / port
POST /api/v1/node/jobs/poll Pull assigned jobs for this provider
POST /api/v1/node/jobs/[id]/complete Mark a job completed / failed + record payout row
POST /api/v1/node/jobs/[id]/events Batch-emit streaming tokens into job_events
POST /api/v1/node/remove Deregister this node
POST /api/v1/node/me Fetch this node's own row
POST /api/v1/node/payments/list List payment_transactions for this node
POST /api/v1/node/payouts/{list,set} Manage provider_payouts rows
Web/mobile routes are server-only — the Supabase service-role client is never imported into browser bundles. The /api/v1/node/* routes are the only ones nodes ever touch, and they verify a Nostr signature before any DB write. OpenAPI 3.1 spec ships as @infernetprotocol/api-schema (raw YAML at packages/api-schema/openapi.yaml).
@infernetprotocol/sdk (packages/sdk-js) — JS/TS SDK with an InfernetClient and an async-iterator chat() helper for the SSE stream.@infernetprotocol/api-schema (packages/api-schema) — OpenAPI 3.1 spec; feed to any generator for Python/Go/Rust clients.@infernetprotocol/deploy-providers (packages/deploy-providers) — cloud-GPU adapters (RunPod today) powering the one-click /deploy page.ghcr.io/profullstack/infernet-provider:0.1.0 and :latest, multi-arch linux/amd64 + linux/arm64. One command boots a provider; see the Quick start above.@infernetprotocol/* packages (cli, sdk, api-schema, deploy-providers, nim-adapter, auth, config, db, gpu, inference, logger, payments). Release workflow + dry-run publish are ready; waiting on an npm Automation token.tooling/dist/homebrew. Tap repo at infernetprotocol/homebrew-infernet. Activates as soon as npm ships.Tag a v*.*.* and .github/workflows/release.yml builds the Docker image and creates a GitHub Release. See docs/RELEASING.md for the full flow.
Bump apps/cli/package.json to the tag's version before tagging. The release workflow fails unless
apps/cli/package.json equals the tag (CI only stamps the npm version), and nodes installed from git
(~/.infernet/source) compare against that file: if it lags, they reinstall on every update check.
So a CLI change ships as: bump apps/cli/package.json in the PR, merge, then tag vX.Y.Z on the merge commit.
The /deploy page (backed by POST /api/deploy/runpod) spins up an Infernet provider node on RunPod using a user-supplied API key. The server proxies the RunPod API call and immediately drops the key — nothing is persisted. The pod boots the infernet-provider image, generates a Nostr keypair, registers itself with the control plane over a signed request, and starts heartbeating.
See docs/CONTRIBUTING.md.
MIT. See LICENSE.
/api/v1/node/* — GPU nodes sign every request with their secp256k1 / BIP-340 keypair; the control plane verifies the signature before touching the DB. No service-role keys ever leave the server.providers.specs.gpus for control-plane job matching.install.sh scans df, finds the biggest writable volume that isn't the root overlay, and symlinks the shard data dir onto it. Works for RunPod /workspace, Vast.ai /data, Lambda /lambda, bare metal /mnt/*, anywhere. Inherited by every plugin including infernet.