# Quickstart — your first plugin

In about ten minutes you will build a plugin that makes every agent on your account end its replies with a
sign-off you choose, publish it privately, install it, and see it work in a chat.

It is the same shape as the official **Caveman** and **My Dude** plugins: one `systemPrompt` middleware that adds a
line to the agent's instructions before each turn.

You need an AgentParley account with a model provider connected and one agent that replies.

## 1. Create the plugin

Skip this step if you take option B below: uploading a zip creates the plugin from its readme.

In the console, open **Plugins → Created → Write in the browser**. Fill in:

- **Name** — `Sign-off`
- **Address** — `sign-off` (lowercase letters, digits, hyphens and underscores, up to 64 characters; it becomes part
  of your plugin's identity and of any tool names it registers)
- **One line about it** — `Ends every reply with a sign-off.`
- **Start from** — any card; you will replace the code.

Press **Create and open editor**.

## 2. Write the code

You can write it in the console editor (option A) or on your machine and upload a zip (option B). The code is the
same.

```ts
globalThis.manifest = {
  settings: [
    {
      key: "signOff",
      title: "Sign-off",
      description: "The words every reply ends with.",
      type: "text",
      default: "Fair winds.",
    },
  ],
};

globalThis.middleware.systemPrompt = async (context) => {
  const signOff = host.settings.get("signOff");
  host.log("debug", `adding sign-off for agent ${context.agentId}`);
  return (
    context.systemPrompt +
    "\n\n## Sign-off\n" +
    `End every reply with the words "${signOff}", as the last words of your final sentence.`
  );
};
```

What each part does:

- `globalThis.manifest.settings` declares a settings form. The user sees a **Sign-off** text field when they
  configure the plugin; your code reads it with `host.settings.get("signOff")`.
- `globalThis.middleware.systemPrompt` is a **middleware hook**. It runs every time an agent on the installing
  account starts a turn, receives the system prompt that turn is about to use, and returns the new one.
- `host.log` writes a line to the plugin's log panel. It needs no permission.

The code calls no `host.fetch`, `host.session` or `host.agents`, so the plugin asks for **no permissions**.

### Option A — the console editor

On the plugin's page, paste the code into the **Code** card (the editor's single file is `index.js`; TypeScript-only
syntax such as type annotations won't work there — the code above is plain JavaScript and works in both). The card's
**Web addresses it can reach** and **Extra permissions** fields are added to your manifest, and they win over the same keys in your code. Press **Save** (⌘S) to check
that it builds.

### Option B — a local folder and a zip

```
sign-off/
  readme.md
  index.ts
  tsconfig.json        (for your editor only — leave it out of the zip)
```

`readme.md`:

```markdown
---
name: Sign-off
description: Ends every reply with a sign-off.
---

# Sign-off

Adds one line to every agent's instructions so each reply ends with the sign-off you set.

## Settings

- **Sign-off** — the words every reply ends with. Default: "Fair winds."

## Permissions

None.
```

`index.ts` is the code above. For type-checking, press **Download SDK types** on the plugin's page (it saves
`agentparley-plugin-sdk.d.ts`) and use a `tsconfig.json` like this:

```json
{
  "compilerOptions": {
    "strict": true,
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "lib": ["ES2022"],
    "types": [],
    "skipLibCheck": true,
    "noEmit": true
  },
  "include": ["index.ts", "agentparley-plugin-sdk.d.ts"]
}
```

Run `npx tsc -p .` to check it. The platform does **not** type-check at publish — it only strips the types — so
this is your safety net. Then zip `readme.md` and `index.ts` (not `tsconfig.json` — the publish refuses files it
doesn't recognize — and leave the `.d.ts` out too, since it would only count as an extra source file).

## 3. Publish

- **Editor:** press **Publish…**. The first version becomes `1.0.0`.
- **Zip:** on **Plugins → Created** press **Upload a plugin** (or drop the zip there) and pick the zip. The readme has
  no `version:`, so the platform uses `1.0` and publishes `1.0.0`.

Publishing bundles your code, discovers the capability (one `systemPrompt` middleware), derives the permissions
(none), and stores version `1.0.0`. Versions are immutable: the next change is `1.0.1` or higher.

Your plugin is **private**: only your account can see and install it. That is exactly what you want while testing.

## 4. Install and configure

Open **Plugins → Browse**. Your plugin is listed marked *private*. Open it — you'll see its capabilities,
**What it can reach** (nothing), and your readme — and press **Install Sign-off**. Leave **All agents** selected and
press **Install on all agents**.

On the installed plugin's page, set **Sign-off** to something you'll recognize, for example `Ahoy, matey.`

## 5. See it work

Open a new chat with any agent and ask it anything. The reply ends with *Ahoy, matey.*

There is nothing to enable per agent: middleware runs for every agent the plugin is installed on, and **All
agents** is the default. (Tools, commands and skills are different — each agent's **Access** tab can narrow those.)

Back on the installed plugin's page, the **logs** panel shows your `adding sign-off for agent …` lines. Logs are
kept for 24 hours.

## 6. Change it

Edit the text and publish the next version, and your install moves to it within about five minutes (the install's
version policy is **Latest** by default). Zip: upload it again; the platform publishes `1.0.1`. Editor: **Publish…**
offers patch, minor and major for any published plugin. If a new version asks
for *more* access — say you add `host.fetch` and an egress
host — it waits on the installed plugin's page under **Update waiting for your OK** until you accept it.

To test changes before publishing, use **Save** in the editor and switch your install to your draft (**Use my draft**) on the **Try it** tab, where you can also chat with an agent running it.

## Where next

- Add a model-callable function: [Tools](plugin-tools.md).
- The other 16 middleware hooks: [Middleware](plugin-middleware.md).
- Make it public: [Publishing](publishing.md).
- Ship a whole crew: [Agent crews](plugin-agent-crews.md).
