Expose code as a Graftcode Receiver

Turn an existing library or module into a Receiver without adding HTTP route handlers, controllers, or transport types on the public surface.

1. Choose the public surface

Expose only intentional public classes and methods. Keep database clients, HTTP objects, streams, framework models, and implementation helpers internal.

Use a plain module with a small, intentional public API. Prefer primitives, plain models, and language arrays. Async return types (Task, Promise, async def, …) are allowed on many Receivers when you need them—results complete on the Receiver; see Invocation lifecycle. Avoid CancellationToken, framework collection interfaces, and non-parsable BCL types on the public surface.

namespace Pricing;
public static class PriceService
{
public static double Calculate(double amount, double discountPercent) =>
amount * (1 - discountPercent / 100);
}
Use primitives and plain models. For the safest cross-runtime contracts, use ISO-8601 strings for dates and string identifiers for IDs. You can also use [parsable framework types](../reference/type-compatibility-matrix.md#parsable-framework-types) such as `System.DateTime` or `System.Guid`; generate the Caller package for each Caller runtime you use. The engine rejects **non-parsable** framework types (for example `List`, `Stream`, `System.Type`) with HTTP `422`.

2. Build the Receiver

dotnet build ./Pricing/Pricing.csproj
## 3. Start Gateway with the real module

Install and run Graftcode Gateway (gg) if you have not already—it hosts your built module, discovers the public surface, and publishes the callable surface. See Run Gateway locally.

gg ./Pricing/bin/Debug/net9.0/Pricing.dll
Adjust paths and runtime versions to the project. Do not copy package IDs, registry URLs, or project keys from examples.

4. Confirm discovery in Vision

Check Gateway output and Graftcode Vision for the expected type and methods. Treat the discovered surface as a review gate: remove accidental public members before Callers install a Graft.

For types beyond the portable baseline, generate a Caller package per Receiver→Caller direction and follow the emitted API.

Next steps