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

# Test a plugin locally

> Install a plugin into a local formae agent and drive it end to end with local schema references, before publishing to the hub.

Before you publish a plugin, run it against a local agent to confirm it works
end to end. The loop is: build and install the plugin, point a forma at its
local schema, and apply against a local agent. This guide covers the local
schema references that let you do this without the plugin being on the hub.

<Steps>
  <Step title="Install the plugin locally">
    From the plugin project, build and install it into the local plugin
    directory:

    ```bash theme={"languages":{"custom":["/languages/pkl.json"]}}
    make install
    ```

    This places the binary, schema, and manifest under
    `~/.pel/formae/plugins/<name>/<version>/`, where a local agent discovers it.
    The agent loads plugins at startup, so restart your local agent after
    installing so it picks the plugin up.

    Whenever you change plugin code, run `make install` again: the agent and the
    conformance tests run against the installed binary, not your source tree.
  </Step>

  <Step title="Reference the local schema">
    A published plugin's schema is fetched from the hub with `package://` imports.
    A plugin you have only installed locally is not on the hub yet, so point at
    its on-disk schema instead. There are two entry points.

    For a new project, scaffold it with the plugin included as a local package.
    The `@local` suffix tells formae to resolve the schema from `--plugin-dir`
    (which defaults to `~/.pel/formae/plugins`) rather than the hub:

    ```bash theme={"languages":{"custom":["/languages/pkl.json"]}}
    formae project init --include myplugin@local
    ```

    To round-trip existing resources, extract with local schema references. This
    emits local file imports against the agent's on-disk `PklProject` paths
    instead of hub `package://` URIs:

    ```bash theme={"languages":{"custom":["/languages/pkl.json"]}}
    formae extract --schema-location local
    ```

    <Note>
      `--schema-location local` requires the CLI and the agent to share a
      filesystem, since the generated imports point at the agent's local plugin
      paths. It is the right choice for a single-host dev loop; use the default
      `remote` once the plugin is published.
    </Note>
  </Step>

  <Step title="Apply and iterate">
    Apply your forma against the local agent and verify the result:

    ```bash theme={"languages":{"custom":["/languages/pkl.json"]}}
    formae apply --mode reconcile --watch my-resource.pkl
    formae inventory resources --query 'stack:my-stack'
    ```

    Iterate on the plugin, re-run `make install`, restart the agent, and apply
    again. Once the resource lifecycle behaves, run the conformance suite (see
    [Conformance tests](/plugin-development/tutorial/11-conformance)) and then
    publish.
  </Step>
</Steps>

## See also

* [Scaffold a new plugin](/plugin-development/guides/scaffold-a-plugin): create the project this guide installs.
* [Build a plugin: local testing](/plugin-development/tutorial/13-local-testing): the same loop inside the tutorial.
* [Conformance tests](/plugin-development/tutorial/11-conformance): validate the plugin against the agent before publishing.
