All SDKs
C#

C# SDK

Vadyl.Client
Available
The C# SDK targets .NET 8+ and .NET 10. Source-generator-backed types for zero-runtime overhead. Native HttpClient transport. Native AOT-compatible.

Install

.NET CLI
dotnet add package Vadyl.Client
NuGet Package Manager
Install-Package Vadyl.Client
Paket
paket add Vadyl.Client
Read the documentation
1. Initialize

Create the client

Configure the client once. Same object reaches every product surface — entities, workflows, agents, realtime.

Program.csC#
using Vadyl.Client;

var vadyl = new VadylClient(new VadylClientOptions
{
    ApiUrl  = "https://api.vadyl.app/v1",
    Token   = Environment.GetEnvironmentVariable("VADYL_TOKEN"),
    Tenant  = "acme",
    Project = "billing",
    // optional — pin to a feature branch
    Branch  = Environment.GetEnvironmentVariable("VADYL_BRANCH"),
});

// Or with DI:
//   services.AddVadylClient(opts => { opts.ApiUrl = "..."; ... });
//   IVadylClient vadyl = sp.GetRequiredService<IVadylClient>();
2. Read

List, filter, paginate

Typed filter expressions, cursor pagination, eager relation loading.

ListOrders.csC#
// Typed filter, sort, pagination, and relation expansion
var recent = await vadyl.Orders.ListAsync(new ListOrderRequest
{
    Filter = new OrderFilter
    {
        Status    = OrderStatus.Paid | OrderStatus.Fulfilled,
        Total     = OrderFilter.Gt(100m),
        CreatedAt = OrderFilter.SinceNow("-30d"),
    },
    Sort     = [new Sort("createdAt", SortDir.Desc)],
    PageSize = 50,
    Include  = ["customer", "items.product"],
});

// recent.Data: IReadOnlyList<Order>
// recent.Page: { Number, Size, TotalCount?, Next?, Prev? }
Console.WriteLine($"{recent.Data.Count} orders, next: {recent.Page.Next}");
3. Write

Create, update, delete with idempotency

Every mutation supports idempotency keys. Retries are safe by default.

CreateCustomer.csC#
// Idempotent create — safe to retry
var customer = await vadyl.Customers.CreateAsync(
    new CustomerCreateInput { Email = "ada@example.com", Name = "Ada Lovelace" },
    idempotencyKey: $"signup:{session.Id}");

// Update with optimistic concurrency
var updated = await vadyl.Customers.UpdateAsync(
    customer.Id,
    new CustomerUpdateInput { Name = "Ada L." },
    ifMatch: customer.ConcurrencyToken);

// Delete (soft-delete on entities with that lifecycle)
await vadyl.Customers.DeleteAsync(customer.Id);
4. Realtime

Subscribe to entity changes

Field names only — never values. Re-read for values through CRUD with proper access enforcement.

Subscribe.csC#
// IAsyncEnumerable streaming subscription with the same filter AST as queries
await foreach (var evt in vadyl.Orders
    .Subscribe(
        new OrderFilter { Status = OrderStatus.Paid },
        kinds: [ChangeKind.Created, ChangeKind.Updated])
    .ReadAllAsync(ct))
{
    // evt.Kind, evt.EntityId, evt.ChangedFields, evt.OccurredAt
    // Field NAMES only — re-read for values
    var order = await vadyl.Orders.ReadAsync(evt.EntityId, ct);
    Console.WriteLine($"paid: {order.Id}");
}
5. Workflows

Start and signal durable workflows

Long-running product behavior that survives process restart. Same client interface; canonical durability underneath.

WorkflowClient.csC#
// Start a durable workflow
var run = await vadyl.Workflows.FulfillOrder.StartAsync(
    new FulfillOrderInput { OrderId = "ord_abc" });

// Send a signal (e.g. from a webhook)
await vadyl.Workflows.FulfillOrder.SignalAsync(
    run.Id,
    "shipped",
    new { TrackingNumber = "1Z..." });

// Query run state
var state = await vadyl.Workflows.FulfillOrder.QueryAsync(run.Id);
6. Agents

Run agents against the product model

Typed plan IR, capability-aware model routing, token accounting — all behind one method.

RunAgent.csC#
// Run an agent — typed plan IR, capability-aware model routing
var run = await vadyl.Agents.SupportAgent.RunAsync(new AgentRunInput
{
    Prompt  = "Refund order #12345 due to defect",
    UserId  = session.UserId,
    Budget  = new AgentBudget { MaxTokens = 50_000, MaxToolCalls = 30 },
});

// Stream the run
await foreach (var step in run.StreamAsync(ct))
    Console.WriteLine($"{step.Kind}: {step.Summary}");

// Recall memory
var facts = await vadyl.Agents.SupportAgent.Memory.RecallAsync(new RecallRequest
{
    Kind    = "preference",
    Subject = session.UserId,
});
7. Errors

Typed error contract

Stable error codes, stable reason codes, correlation IDs, and explainability links.

Errors.csC#
try
{
    await vadyl.Orders.UpdateAsync(id, new OrderUpdateInput { Status = OrderStatus.Refunded });
}
catch (VadylAccessDeniedException ex)
{
    Console.WriteLine($"{ex.ReasonCode} ({ex.CorrelationId})");
}
catch (VadylConflictException)
{
    // optimistic-concurrency mismatch — re-read and retry
}
catch (VadylValidationException ex)
{
    foreach (var e in ex.FieldErrors) Console.WriteLine($"{e.Field}: {e.ReasonCode}");
}
catch (VadylException ex)
{
    Console.WriteLine($"{ex.Code}: {ex.Message}");
}
8. Authoring runtime

Define handlers, workflows, agents

The same package you use as a client also powers your authored runtime — defineCoreHandler, defineWorkflow, defineAgent.

Handlers/Orders/Charge.csC#
using Vadyl.Authoring;

public class ChargeOrderHandler : ICoreHandler<ChargeInput, ChargeResult>
{
    public async Task<ChargeResult> InvokeAsync(IRuntimeContext ctx, ChargeInput input, CancellationToken ct)
    {
        var order  = await ctx.Entities.Order.ReadAsync(input.OrderId, ct);
        var charge = await ctx.Connections.Stripe.CreateChargeAsync(new StripeChargeInput
        {
            Amount         = order.Total,
            Currency       = order.Currency,
            IdempotencyKey = $"charge:{order.Id}",
        }, ct);

        await ctx.Entities.Order.UpdateAsync(order.Id, new OrderUpdate
        {
            Status   = OrderStatus.Paid,
            ChargeId = charge.Id,
        }, ct);

        await ctx.Events.EmitAsync("order.paid", new { OrderId = order.Id }, ct);
        return new ChargeResult(true, charge.Id);
    }
}

What you get

Source-generator typed

Records and interfaces emitted at build-time from your project's contract manifest. Compile-time safety end-to-end.

Manifest verification

The SDK refuses to talk to a server whose generated-format version it does not support. Fail closed.

Realtime built-in

WebSocket and SSE subscriptions through ClientWebSocket. IAsyncEnumerable streams. Reconnect-safe.

DI-friendly

AddVadylClient extension on IServiceCollection. Plays naturally with ASP.NET Core, MAUI, Blazor.

Native AOT

Trimming-safe and AOT-compatible. Ships as a single binary.

Branch-aware

Configure branches per environment via VadylClientOptions.Branch. Sandbox testing without leaving prod.

OpenTelemetry

Built-in ActivitySource and Meter integration. Spans on every canonical operation.

Agent primitives

VadylClient.Agents exposes the Agent plane: definitions, runs, memory, MCP exposure.

Connections

Typed governed-connection clients per registered governed connection.

Build with the C# SDK in minutes.

Install the package and work with your product model through typed entities, workflows, agents, and events.