> ## Documentation Index
> Fetch the complete documentation index at: https://forst-lang.org/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Plugins

> Extend `forst generate` with semantic plugins (work in progress).

Forst plugins generate integration files directly from your typechecked backend services.

When you run `forst generate`, the compiler typechecks your Forst code and projects the resulting type definitions and function signatures into an in-memory snapshot. The compiler then executes your configured plugin binaries and passes this snapshot to them over standard input.

Plugins emit generated code—such as JSON Schema files, RPC contract definitions, or framework route handlers—into dedicated output folders. Your application imports these generated outputs, ensuring external contracts and routers stay synchronized with your backend code without manual duplication. Because generated files are written exclusively to designated output directories, running `forst generate` updates your generated code without overwriting hand-written source files.

<Warning>
  **Generate plugins are work in progress.** The stdin/stdout protocol, official emitters, resolver behavior, and CLI download path are usable for experimentation and early adoption, but they may change without independent plugin semver. Pin your compiler and `@forst/cli` version; re-run `forst generate` and read plugin diagnostics after every upgrade.
</Warning>

## Work in progress and known limitations

Semantic plugins and the official emitters are under active development. The table below lists current constraints—not a promise of future design.

| Area                             | Status                                                                                                                                                                                                                                                                     |
| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Plugin versioning**            | No independent semver yet. Official binaries ship in the same GitHub release as the compiler. `@forst/cli` downloads one plugins bundle per compiler version—you cannot pin `forst-gen-orpc` separately from `forst`, and `ftconfig.json` has no per-plugin version field. |
| **Protocol stability**           | Snapshot contract is **protocol v1** (`protocolVersion: 1`). Breaking snapshot changes bump that number in the compiler; there is no automated migration tooling for custom plugins yet.                                                                                   |
| **`ftconfig` validation**        | `generate.plugins[].opt` is opaque JSON. Invalid options fail at plugin runtime with a parse or logic error, not when `ftconfig.json` is loaded.                                                                                                                           |
| **Type and constraint coverage** | Emitters map a subset of Forst types and builtin constraints. Unknown kinds, type guards, channels, function types, and Go interop types often become warnings or empty schemas instead of full-fidelity output.                                                           |
| **Official emitters**            | jsonschema, oRPC, file-routes, and react-router plugins target specific conventions (`.Router()`, file layout under `routesRoot`). They are not yet general-purpose generators for every framework or deployment shape.                                                    |
| **Distribution**                 | No plugin registry or npm packages for official plugins. Custom plugins are executables you build locally and reference via `cmd`.                                                                                                                                         |
| **Host behavior**                | Each plugin run has a 30s timeout. Plugins receive resolved semantics only—no source tokens, AST, or function bodies.                                                                                                                                                      |

If you rely on generated artifacts in CI or production, pin the compiler, regenerate in CI or commit outputs, and treat plugin warnings as signals to fix before shipping.

## Quickstart

Add a plugin to the `generate.plugins` array in `ftconfig.json`:

```jsonc theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
{
  "generate": {
    "plugins": [
      {
        "name": "jsonschema",
        "cmd": "forst-gen-jsonschema",
        "out": "generated/jsonschema",
        "opt": {
          "draft": "2020-12"
        }
      }
    ]
  }
}
```

Run `forst generate` from your terminal:

```bash theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
forst generate ./my-service
```

This creates `generated/jsonschema/schema.json` alongside your generated TypeScript client. You can now import `schema.json` directly into your API gateway, validation pipeline, or external documentation tools.

Build official plugin binaries from the Forst repo with `task build` (compiler + plugins land in `bin/`). GitHub Releases and `@forst/cli` ship the same plugin binaries next to the compiler; bare `cmd` names resolve automatically.

## Example project

The repo ships a runnable boundary at `examples/in/plugins/` that exercises every official plugin from real `.ft` sources (RPC catalog, file routes, and React Router handlers). See that directory's README for commands.

## Resolving plugin executables (`cmd`)

Each `generate.plugins[].cmd` value resolves as follows:

| Form                                  | Resolution                                                                    |
| ------------------------------------- | ----------------------------------------------------------------------------- |
| `forst-gen-jsonschema`                | Directory of the running `forst` binary, then `FORST_PLUGIN_DIR`, then `PATH` |
| `./bin/forst-gen-jsonschema`          | Relative to the ftconfig boundary root                                        |
| `/usr/local/bin/forst-gen-jsonschema` | Used as-is (absolute path)                                                    |

When you invoke `forst` through `@forst/cli`, the CLI downloads official plugin binaries into the same version cache directory as the compiler only when `forst generate` runs against an `ftconfig.json` that lists bare official plugin names in `generate.plugins`, then prepends that directory to `PATH` before spawning.

Plugin `out` directories are owned exclusively by the plugin. On each run, `forst generate` removes stale files under `out` that the plugin did not emit. Diagnostics with `severity: "error"` fail the generate command; warnings are logged only.

Invalid `opt` JSON in `ftconfig.json` fails the plugin at runtime with a parse error.

## What you can build with plugins

Plugins bridge Forst's type system with any external system or toolchain. Because plugins receive fully resolved types, constraint chains, and function signatures, you can automate any downstream output that derives from backend service definitions:

* **Validation and data schemas.** Convert type constraint chains into JSON Schema, Zod, Effect Schema, or custom validation rules for external clients, API gateways, and message queues.
* **API contracts and specifications.** Derive end-to-end typed contract trees, OpenAPI specs, AsyncAPI definitions, GraphQL schemas, or client SDKs for RPC frameworks, REST endpoints, and message brokers.
* **Framework and HTTP routing.** Generate route tables, parameter mappers, middleware hooks, and request dispatchers for web servers and full-stack frameworks.
* **Full-stack data integration.** Produce server-side data loaders, resource route handlers, or form actions so UI frameworks can fetch Forst data without modifying your frontend source code.
* **Persistence and database definitions.** Translate shape types and constraints into database schema migrations, SQL constraint assertions, ORM model mappings, or seed fixtures.
* **Infrastructure and cloud topology.** Generate IaC definitions (Terraform, Pulumi, AWS CDK, Kubernetes CRDs) or API gateway policies directly from backend service declarations and provider dependencies.
* **CI/CD and pipeline validation.** Produce GitHub Actions workflows, contract compatibility matrices, or breaking-change checkers between git revisions.
* **Automated testing and mock suites.** Build deterministic test fixtures, fake service implementations, property-based test generators, or contract-testing suites automatically from service shapes.

## Official plugin packages

Official plugins are shipped alongside the compiler as standalone binaries. Each emitter is early-stage; output file names, `opt` fields, and generated APIs may change while plugin versioning matures.

### `forst-gen-jsonschema`

Generates standard JSON Schema files from Forst shapes and constraint chains.

* **Use case:** Share strict type validation with external services, API gateways, or OpenAPI documentation.
* **Key behavior:** Maps built-in constraints (`Min`, `Max`, `HasPrefix`, `Contains`) to schema properties. On maps, `Min`/`Max` become `minProperties`/`maxProperties`. Emits a warning for runtime type-guard functions like `Email()` rather than guessing a format string.

```jsonc theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
{
  "name": "jsonschema",
  "cmd": "forst-gen-jsonschema",
  "out": "generated/jsonschema",
  "opt": {
    "draft": "2020-12"
  }
}
```

### `forst-gen-orpc`

Generates Zod schemas and procedure contracts for oRPC or tRPC applications.

* **Use case:** Connect frontend web apps to Forst backend services using end-to-end typed RPC.
* **Key behavior:** Reads contract types marked with `.Router()`. Generates `zod.ts`, `contract.ts`, and `invoke.ts`. Supports stream returns as subscriptions and maps optional query or mutation hints.

```jsonc theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
{
  "name": "orpc",
  "cmd": "forst-gen-orpc",
  "out": "generated/orpc",
  "opt": {
    "markers": ["Router"],
    "style": "orpc",
    "queries": ["catalog.Catalog.GetOrder"]
  }
}
```

### `forst-gen-file-routes`

Generates a sealed HTTP route registry from file paths under a target directory.

* **Use case:** Build RESTful HTTP APIs where file layout determines URL structure.
* **Key behavior:** Converts paths like `app/api/orders/$id.ft` into route pattern `/api/orders/:id`. Generates handler wrappers, path parameter bindings, and a central `dispatch()` function. Skips `.Router()` types declared outside `opt.routesRoot` (for example RPC catalogs in `catalog/`). Skips HTTP members whose bound function is not runnable (same as the React Router plugin) and emits an error diagnostic.

```jsonc theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
{
  "name": "file-routes",
  "cmd": "forst-gen-file-routes",
  "out": "generated/api",
  "opt": {
    "routesRoot": "app/api",
    "paramStyle": "$id"
  }
}
```

### `forst-gen-react-router`

Generates React Router and Remix resource routes and server loaders.

* **Use case:** Integrate Forst data fetching into React Router v7 or Remix full-stack applications.
* **Key behavior:** Generates `forstApiRoutes` arrays, resource handler modules (`loader` and `action`), and helper functions for page modules. Never writes into your `app/` UI source folder.

```jsonc theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
{
  "name": "rr-ssr",
  "cmd": "forst-gen-react-router",
  "out": "generated/rr",
  "opt": {
    "routesRoot": "app/api",
    "invoke": "package"
  }
}
```

### `forst-gen-echo`

Development-only manifest of type and function ids in the semantic snapshot. Use it to verify `generate.plugins[]` wiring — not for production artifacts.

```jsonc theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
{
  "name": "echo",
  "cmd": "forst-gen-echo",
  "out": "generated/echo"
}
```

## How to write a custom plugin

You can write a custom plugin in Go or any language that can read standard input and write standard output.

### Why write a custom plugin?

Write a custom plugin when you need to transform Forst type metadata into custom project files. Examples include:

* Generating database migration scripts or SQL `CHECK` constraints from type assertions.
* Emitting GraphQL schema definitions (`.graphql`) from exported shape types.
* Producing custom SDKs for internal SDK clients or language runtimes.
* Generating infrastructure config (Terraform, AWS CDK, Kubernetes manifests) based on service definitions.

### Under the hood: The semantic snapshot model

Plugins do not receive raw source tokens or abstract syntax trees (AST). Instead, `forst generate` typechecks your Forst code and projects a structured JSON payload called the **semantic snapshot** (the same typecheck also feeds the TypeScript client).

The snapshot contains resolved, fully-qualified facts about your codebase:

* **Packages:** Module layout, directories, files, and exported type/function IDs.
* **Types:** Resolved primitives, shapes, field names, optionality, tags, and ordered constraint chains.
* **Functions:** Exported declarations, parameters, synthesized input shapes, return types, and nominal error sets.

Because plugins consume resolved type semantics rather than syntax, your plugin logic remains clean and predictable regardless of how the source code was formatted.

### Step 1: Implement the JSON protocol

Plugins read a single JSON request from `stdin` and write a single JSON response to `stdout`.

Here is a minimal Go plugin using the official `forst/internal/genplugin` helper package:

```go theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
package main

import (
	"fmt"
	"strings"

	"forst/internal/genplugin"
	"forst/internal/semantic"
)

func main() {
	genplugin.Run(emitCustomManifest)
}

func emitCustomManifest(req *semantic.GenerateRequest) (semantic.GenerateResponse, error) {
	var builder strings.Builder
	builder.WriteString("# Exported Service Types\n\n")

	for _, id := range genplugin.ExportedPackageTypeIDs(req) {
		t := req.Types[id]
		fmt.Fprintf(&builder, "- %s (kind: %s)\n", id, t.Kind)
	}

	return semantic.GenerateResponse{
		ProtocolVersion: semantic.ProtocolVersion,
		Files: []semantic.OutputFile{
			{
				Path:    "SUMMARY.md",
				Content: builder.String(),
			},
		},
	}, nil
}
```

### Step 2: Register your plugin executable

Build your executable and reference it in your `ftconfig.json`:

```jsonc theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
{
  "generate": {
    "plugins": [
      {
        "name": "custom-summary",
        "cmd": "./bin/my-custom-plugin",
        "out": "generated/summary"
      }
    ]
  }
}
```

When you run `forst generate`, the compiler executes `./bin/my-custom-plugin`, passes the snapshot, and writes `generated/summary/SUMMARY.md`.

## Inspecting snapshots for debugging

You can inspect the exact JSON snapshot emitted by the compiler without executing any plugins by using the `--dump-semantic` flag:

```bash theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
forst generate --dump-semantic ./my-service
```

This prints the complete `GenerateRequest` payload to standard output, making it easy to test and debug custom plugin transformations.
