[@layout]: ../docs.layout.md

# Plugin configuration

Configure a reusable Plugin for each project. Package a greeting command and set
its options to print `Welcome`.

---

## Define a configurable package

Start with a working [PathMX project](../start/first-site.guide.md).

A package can export a schema-validated factory using `definePlugin`. Core reads
its options from `package.json` under `pathmx.plugins[packageName]`, validates them,
and constructs an ordinary Plugin. Options are inferred from the schema, including
defaults.

Create a sibling directory named `greeting` beside your project. In that directory,
create `package.json`:

```json
{
  "name": "@example/greeting",
  "version": "1.0.0",
  "type": "module",
  "exports": { ".": "./plugin.ts" },
  "pathmx": { "plugin": "." },
  "peerDependencies": { "@pathmx/core": "^0.6.0" },
  "dependencies": { "zod": "^4.4.3" }
}
```

The `exports` entry exposes the factory; `pathmx.plugin` identifies that export as
the package Plugin. Create `greeting/plugin.ts`:

```ts
import { definePlugin } from "@pathmx/core"
import * as z from "zod/mini"

export default definePlugin({
  config: z.strictObject({
    label: z._default(z.string(), "Hello"),
  }),
  create(config) {
    return {
      id: "greeting",
      commands(group) {
        group.command("hello").action(() => console.log(config.label))
      },
    }
  },
})
```

---

## Install, configure, and run

From your consuming project root, install the local package:

```sh
bun add ../greeting
```

Add its activation and options to your project's `package.json`, preserving the
existing dependencies and scripts:

```json
{
  "pathmx": {
    "plugins": {
      "@example/greeting": { "label": "Welcome" }
    }
  }
}
```

Run the command from that project root:

```sh
bun run pmx greeting hello
```

It prints `Welcome`. Change `label` to change the greeting; use `{}` for the default
`Hello`. A number instead of a string reports the invalid manifest option path.

---

## Configure in a repository Plugin

The same exported factory is callable in `plugins/greeting.plugin.ts`:

```ts
import GreetingPlugin from "@example/greeting"
export default GreetingPlugin({ label: "Welcome" })
```

Both paths validate the options. Calling without arguments validates `{}`; required
options still fail. Direct overrides do not merge manifest settings automatically.
Ordinary Plugins and presets without a configuration schema accept only `{}`.
A configured factory's `create(config)` may return a Plugin, a factory, or an
ordered Plugin preset. For example, Analytics composes its collector and page Event
namespace through the same configured factory:

```ts
import Analytics from "@pathmx/analytics"

export default Analytics({ retainDays: 90, actors: false })
```

Save this as `plugins/analytics.plugin.ts` when configuring Analytics programmatically;
choose either this entrypoint or its manifest activation.

Manifest options are JSON data. Runtime services and callbacks belong in
programmatic composition. Configuration is resolved during construction and is not
a mutable global registry. Browser publication currently rejects nonempty manifest
options rather than implicitly publishing them or reconstructing different defaults.
For a [browser publication](./core.reference.md#browser-publications), omit this
package from `pathmx.plugins` and use the repository Plugin above to explicitly
compose its options. Keep it installed as a dependency. Repository Plugin code and
its options are bundled for the browser, so include only public values and
browser-compatible behavior; credentials and server-only services stay on the
server.
