NetWiv

Quickstart

Install the CLI, create an app, run it, publish it. Then the smallest C# and frontend code that talk to each other.

NetWiv is not on NuGet.org yet. Its packages come in a ZIP on the GitHub release page, and that folder acts as your package source.

You need

  • .NET 8 or later SDK
  • Node.js ^20.19 or 22.12+
  • The OS WebView: WebView2, WebKitGTK 4.1 or WKWebView

Set up a coding agent

netwiv mcp runs a read-only MCP server from your project’s CLI. Your agent reads the guides for that NetWiv version and the project’s configuration, permissions and commands.

Let your agent do it

Paste this prompt into your coding agent. It installs what is missing, connects the server, offers the NetWiv skills in Claude Code or Codex and checks the connection.

Set it up yourself

Choose your coding agent.

  1. Add the NetWiv marketplace

    /plugin marketplace add NetWiv/skills
  2. Install the skills

    /plugin install netwiv@netwiv
  3. Reload plugins

    /reload-plugins

The skills work with every NetWiv version; version-specific guides come from your project’s CLI. Projects made with netwiv new already include .mcp.json: run dotnet tool restore once, and approve the netwiv server when Claude Code first loads it.

  1. Add the NetWiv marketplace

    codex plugin marketplace add NetWiv/skills
  2. Install the skills

    codex plugin add netwiv@netwiv
  3. Restore the project’s CLI

    dotnet tool restore
  4. Register the server in ~/.codex/config.toml

    [mcp_servers.netwiv]
    command = "dotnet"
    args = ["tool", "run", "netwiv", "--", "mcp"]

Codex installs the skills for all your projects. Start Codex from the project folder so dotnet tool run finds the project’s CLI; a restart loads the skills and the server.

  1. Restore the project’s CLI

    dotnet tool restore
  2. Add .cursor/mcp.json to the project

    {
      "mcpServers": {
        "netwiv": {
          "command": "dotnet",
          "args": ["tool", "run", "netwiv", "--", "mcp"]
        }
      }
    }

The same registration as the project’s .mcp.json.

  1. Restore the project’s CLI

    dotnet tool restore
  2. Register a stdio server

    command:   dotnet
    args:      tool run netwiv -- mcp
    transport: stdio

Start it from the project folder. Before a project exists, a globally installed CLI serves the guides with netwiv mcp.

  1. Download the packages

    Get the ZIP from the release page and unzip it. The commands below assume it went to your Downloads folder; change the path if not. Keep the folder: new projects point to it.

    Download NetWiv-0.2.9-packages.zip

    The release also has SHA256SUMS to verify the ZIP.

  2. Install the CLI

    Run this in the unzipped folder. $feed remembers where the packages are. If the CLI is already installed, use update instead of install.

    Set-Location $HOME\Downloads\NetWiv-0.2.9-packages
    $feed = (Resolve-Path .\packages).Path
    dotnet tool install --global NetWiv.Cli --version 0.2.9 --add-source $feed
    cd ~/Downloads/NetWiv-0.2.9-packages
    feed="$(pwd)/packages"
    dotnet tool install --global NetWiv.Cli --version 0.2.9 --add-source "$feed"
    export PATH="$HOME/.dotnet/tools:$PATH"
  3. Create an app

    Use the same terminal so $feed is still set. React is the default; netwiv new --list shows the six starters: React, Vue, Svelte and Angular with TypeScript, Blazor WebAssembly and Blazor Hybrid.

    Set-Location $HOME    # or wherever you keep projects
    netwiv new MyNetWivApp --template react --source $feed
    Set-Location MyNetWivApp
    cd ~    # or wherever you keep projects
    netwiv new MyNetWivApp --template react --source "$feed"
    cd MyNetWivApp
  4. Run it

    npm ci installs @netwiv/api from the project’s vendor folder. desktop:dev generates bindings, starts Vite and opens the window; C# edits restart the backend.

    npm ci
    npm run desktop:dev
    npm ci
    npm run desktop:dev
  5. Publish

    Self-contained .NET by default; add --aot for NativeAOT. Output goes to target/.

    dotnet tool run netwiv -- build
    dotnet tool run netwiv -- build --aot
    dotnet tool run netwiv -- build
    dotnet tool run netwiv -- build --aot

The window that opens

The React starter on macOS after one call. The frontend reached the C# greet command, which counted the call in managed state.

The NetWiv React starter window: "Your frontend is ready. Call the C# backend.", a name field with Call greet, the answer "Hello, React!" with a call count of 1, and a list of files to edit.

The smallest app

Trimmed from the templates, which also show the call state and wire the dev server.

Hover a highlighted line to see its partner.

src-netwiv/Program.cs
using System.Text.Json.Serialization;using NetWiv;using NetWiv.Platform.Desktop; [assembly: CommandJsonContext(typeof(AppJsonContext))][assembly: GenerateFrontendBindings] internal static class Program{    [STAThread]    private static void Main()    {        using var app = new Builder()            .UseRuntime(new DesktopRuntime())            .Metadata(new AppMetadata("My app", "0.1.0", "dev.example.myapp"))            .UseEmbeddedAssets()            .UseEmbeddedConfig(EmbeddedConfigMode.Production)            .InvokeHandler("greet")            .Window("main", "My app", "index.html", 900, 680)            .Build();        app.Run();    }} public static class Commands{    [Command]    public static string Greet(string name) => $"Hello, {name}!";} [JsonSerializable(typeof(string))]public partial class AppJsonContext : JsonSerializerContext;
src/App.tsx
import { useState } from 'react';import { commands } from './generated/commands.js'; export default function App() {  const [message, setMessage] = useState('');  async function greet() {    setMessage(await commands.greet({ name: 'World' }));  }  return <button onClick={greet}>{message || 'Greet'}</button>;}
src/App.vue
<script setup lang="ts">import { ref } from 'vue';import { commands } from './generated/commands.js'; const message = ref('');async function greet() {  message.value = await commands.greet({ name: 'World' });}</script> <template>  <button @click="greet">{{ message || 'Greet' }}</button></template>
src/App.svelte
<script lang="ts">  import { commands } from './generated/commands.js';   let message = $state('');  async function greet() {    message = await commands.greet({ name: 'World' });  }</script> <button onclick={greet}>{message || 'Greet'}</button>
src/app.ts
import { Component, signal } from '@angular/core';import { commands } from './generated/commands.js'; @Component({  selector: 'app-root',  template: `<button (click)="greet()">{{ message() || 'Greet' }}</button>`,})export class App {  message = signal('');  async greet() {    this.message.set(await commands.greet({ name: 'World' }));  }}
frontend/Pages/Home.razor
@page "/"@inject NetWiv.Generated.NetWivCommands Commands <button @onclick="Greet">@(Message ?? "Greet")</button> @code {    private string? Message;     private async Task Greet()    {        Message = await Commands.GreetAsync("World");    }}
Shared/App.razor
@inject NetWiv.Generated.NetWivCommands Commands <button @onclick="Greet">@(Message ?? "Greet")</button> @code {    private string? Message;     private async Task Greet()    {        Message = await Commands.GreetAsync("World");    }}

Blazor calls C# through NetWivCommands, a typed client each build generates from the commands. Its JSON context and shared types live in the starter’s contracts/ project instead of Program.cs. Values cross JavaScript as JSON text, so long and decimal stay exact.

The blazor-hybrid starter runs this component inside the desktop process on managed .NET, on Windows, Linux and macOS, calling C# through the same generated client. It targets .NET 8 by default; set NetWivBlazorTargetFramework to net9.0 or net10.0 to move the app and its matching Microsoft component packages together. Its shared UI can also be published as WebAssembly. Hybrid with NativeAOT is experimental and needs an explicit opt-in.

CLI at a glance

CommandWhat it does
netwiv new NAME -t TEMPLATEnetwiv new --list# six startersCreate a project with SDK references, local CLI and feed
netwiv devRun with bindings, dev server and backend restarts
netwiv build# self-contained .NETnetwiv build --aot# NativeAOTnetwiv build --framework-dependent# installed runtimenetwiv build -t osx-arm64 -b app,dmg# target and bundlesPublish the app; bundles when the config enables them
netwiv infoShow the CLI and .NET SDK versions, OS and config
netwiv mcpdotnet tool run netwiv -- mcp# project CLIRun the read-only MCP server for coding agents on stdio. New projects register the second form in .mcp.json

Next