> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.apologist.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.apologist.ai/_mcp/server.

# Configuring Scripture Plugins

> Attach hosted or external Scripture plugins that run when an Agent quotes or cites a verse

Scripture plugins add your own HTML next to a quotation or citation. Each plugin receives the raw reference and whether the marker is inline or block. Plugins never see fetched verse text or each other's output. The Agent sanitizes and composes the fragments.

Built-in verse lookup stays a first-party setting on the **Scripture** tab. It is available on every plan and is not a plugin.

## Purpose

Use plugins when you want a popout, a link into your own Scripture UI, or another reference-specific fragment alongside (or instead of) the built-in verse text.

## Prerequisites

* A Pro or Enterprise plan. The **Scripture Plugins** capability and catalog are locked on Free and Basic.
* Scripture Plugins enabled as a team feature. The capability is hidden when that feature is off.
* The Agent's **Scripture Plugins** capability turned on.
* An HTTPS external endpoint, or hosted JavaScript that defines `handle`.

## Steps

#### Create a Plugin In the Catalog

On the Agents list, select **Scripture Plugins**. Add a plugin, choose **Type** (Quote, Cite, or Both), then choose **Mode** (Hosted or External).

* **Hosted** stores a **Handle Function** and optional **Secrets**. The Agent runs `handle` in an isolate. **Implementation** includes **Handler Specifications**.
* **External** stores an **External Endpoint URL** and an optional **External Endpoint Secret**. The Agent posts the reference to your HTTPS endpoint. **Implementation** includes **Endpoint Specifications**.

#### Attach the Plugin To an Agent

Open the Agent and use the **Scripture Plugins** relation. Attach a team-owned or official (global) plugin, toggle it active on this Agent, and drag to set compose order.

#### Keep Or Turn Off Built-In Handling

On **General → Scripture**, **Built-in Scripture Handling** stays available on every plan. Leave it on to keep today's verse fetch in the quotation or citation body. Turn it off if plugins should supply the replacement. Plugins still run when the selected Bible is static.

#### Save And Confirm

Save the Agent, then ask a question that produces a quotation or citation. Confirm the composed HTML in the chat UI. Chat uses `html.summary` inline. If `html.content` is set, hovering the summary opens that HTML below it, the same way inline citations work. API, channel, and voice surfaces use built-in plain text when that setting is on, otherwise `text`. If the value for that surface is omitted or the plugin returns `null`, the marker is replaced with an empty string. A plugin error uses `[John 3:16 — verse unavailable]`.

## Shared Payload

Both modes receive the same JSON. Hosted `handle` also receives `secrets`. External endpoints never receive secrets.

```json
{
  "type": "quote",
  "reference": "John 3:16",
  "display": "inline",
  "bible": { "id": "123", "abbreviation": "ESV", "language": "en" },
  "language": "en"
}
```

`display` is `block` when the marker sits directly on a markdown blockquote line (`> {{QUOTE:John 3:16}}`), the same rule built-in quotations use. Otherwise it is `inline`.

Return:

```json
{
  "html": {
    "summary": "inline content",
    "content": "html shown on hover of summary"
  },
  "text": "plain-text fallback"
}
```

`html.summary` can include HTML, such as an icon. If `html.content` is `null` or omitted, chat treats `summary` as the raw replacement. If `content` is set, `summary` is the inline trigger and `content` opens below it on hover. The hover panel is 16rem wide unless an element in `html.content` sets an explicit `width` (for example `<div style="width: 32rem">`), which expands the panel up to the viewport. Chat uses `html` only. API, channel, and voice surfaces use `text` only. If the value for that surface is omitted or empty, or the plugin returns `null`, the marker is replaced with an empty string. A plugin error (timeout, non-2xx, invalid JSON, or isolate throw) uses `[John 3:16 — verse unavailable]`. Built-in fetch uses that same placeholder when verse lookup is on and the verse cannot be retrieved.

## Hosted Example

The catalog pre-fills **Handle Function** with this shape. **Handler Specifications** on **Implementation** documents the arguments and return value.

```javascript
async function handle({ type, reference, display, bible, language, secrets }) {
    const res = await fetch(
        'https://example.com/plugin?ref=' + encodeURIComponent(reference),
        { headers: { Authorization: 'Bearer ' + secrets.api_key } }
    );
    const data = await res.json();
    return {
        html: {
            summary: reference,
            content: data.summary,
        },
        text: reference,
    };
}
```

Host `fetch` is HTTPS only. Private, loopback, and metadata hosts are blocked. The isolate has no `process`, `require`, or Node modules.

## External Example

`POST` the shared payload to your **External Endpoint URL**. When **External Endpoint Secret** is set, the Agent signs the raw JSON body and sends `X-Apologist-Signature: sha256=...`. **Endpoint Specifications** on **Implementation** shows the request and response.

Respond with JSON:

```json
{
  "html": {
    "summary": "Open In Our Library",
    "content": "<p>John 3:16 in our library.</p>"
  },
  "text": "Open In Our Library"
}
```

A timeout, a non-2xx status, or an invalid return skips that plugin and uses `[John 3:16 — verse unavailable]` when no other fragment filled the marker. Other plugins still run.

## Composition

Each quotation or citation is wrapped for CSS hooks: `.apg-scripture-quote` or `.apg-scripture-cite`. Built-in verse or citation text, when enabled, comes first. Plugin fragments follow in attach order.

When `html.content` is set:

```html
<span class="apg-scripture-quote">
  <span class="apg-scripture-hover">
    <span class="apg-scripture-summary"><!-- inline --></span>
    <span class="apg-scripture-content"><!-- hover panel --></span>
  </span>
</span>
```

Returned HTML is sanitized. `<script>` tags and event handlers are stripped.

## Cautions

Treat hosted secrets and external endpoint secrets as credentials. They are stored encrypted in Console and are never sent to an external endpoint.

Hosted JavaScript runs in an isolate with a short timeout and fetch limits. Do not rely on it for long-running work.

## Troubleshooting

* **The Scripture Plugins capability or button is missing.** Scripture Plugins must be enabled as a team feature, the plan needs the `agent.scripture_plugins` entitlement (Pro or Enterprise), and the Agent needs the **Scripture Plugins** capability turned on.
* **A plugin never appears in chat.** Confirm both the catalog row and the Agent attachment are active, and that **Type** matches the marker (Quote or Cite). Both runs on quotations and citations.
* **Only the verse text appears.** Built-in handling is on and the plugin returned empty or invalid HTML. Check the external endpoint status or isolate `handle` return value.
* **The marker disappears.** The plugin returned no `html` for chat, or no `text` for API, channel, and voice. Return the field for that surface, or return `null` when the plugin has nothing to show.
* **The marker becomes verse unavailable.** The plugin threw, timed out, or returned a non-2xx or invalid JSON response. Return `null` when there is no content. Built-in fetch also uses this placeholder when verse lookup is on and the verse cannot be retrieved.
* **A hover panel does not appear.** `html.content` is missing or empty, so chat treats `html.summary` as raw HTML. If `html` is omitted, chat leaves the marker empty instead of using `text`.

## Next Step

Continue to [Customizing Instructions](/console/configuration/customizing-instructions).