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

# Built-in Plugins

> Plugins shipped with Mibyan that run automatically via lifecycle hooks — disk-cleanup and friends

Mibyan ships a small set of plugins bundled with the repository. They live under `<repo>/plugins/<name>/` and load automatically alongside user-installed plugins in `~/.mibyan/plugins/`. They use the same plugin surface as third-party plugins — hooks, tools, slash commands — just maintained in-tree.

See the [Plugins](/desktop/user-guide/features/plugins) page for the general plugin system, and [Build a Mibyan Plugin](/desktop/developer-guide/plugins/overview) to write your own.

## How discovery works

The `PluginManager` scans four sources, in order:

1. **Bundled** — `<repo>/plugins/<name>/` (what this page documents)
2. **User** — `~/.mibyan/plugins/<name>/`
3. **Project** — `./.mibyan/plugins/<name>/` (requires `mibyan_ENABLE_PROJECT_PLUGINS=1`)
4. **Pip entry points** — `mibyan_agent.plugins`

On name collision, later sources win — a user plugin named `disk-cleanup` would replace the bundled one.

`plugins/memory/` and `plugins/context_engine/` are deliberately excluded from bundled scanning. Those directories use their own discovery paths because memory providers and context engines are single-select providers configured through `mibyan memory setup` / `context.engine` in config.

## Bundled plugins are opt-in

Bundled plugins ship disabled. Discovery finds them (they appear in `mibyan plugins list` and the interactive `mibyan plugins` UI), but none load until you explicitly enable them:

```bash theme={null}
mibyan plugins enable disk-cleanup
```

Or via `~/.mibyan/config.yaml`:

```yaml theme={null}
plugins:
  enabled:
    - disk-cleanup
```

This is the same mechanism user-installed plugins use. Bundled plugins are never auto-enabled — not on fresh install, not for existing users upgrading to a newer Mibyan. You always opt in explicitly.

To turn a bundled plugin off again:

```bash theme={null}
mibyan plugins disable disk-cleanup
# or: remove it from plugins.enabled in config.yaml
```

## Currently shipped

The repo ships these bundled plugins under `plugins/`. All are opt-in — enable them via `mibyan plugins enable <name>`.

| Plugin | Kind | Purpose |
| - | - | - |
| `disk-cleanup` | hooks + slash command | Auto-track ephemeral files and clean them on session end |
| `security-guidance` | hooks | Pattern-match dangerous code on `write_file`/`patch` and append a security warning (or block) — 25 rules (Apache-2.0 fork of Anthropic's `claude-plugins-official` patterns) |
| `observability/langfuse` | hooks | Trace turns / LLM calls / tools to [Langfuse](https://langfuse.com) |
| `teams_pipeline` | standalone | Microsoft Teams meeting pipeline — Graph-backed, transcript-first meeting summaries |
| `spotify` | backend (7 tools) | Native Spotify playback, queue, search, playlists, albums, library |
| `google_meet` | standalone | Join Meet calls, live-caption transcription, optional realtime duplex audio |
| `image_gen/openai` | image backend | OpenAI GPT Image 2 and 2.5 Flare/Sunburst generation and editing (API key) |
| `image_gen/openai-codex` | image backend | OpenAI image generation via Codex OAuth |
| `image_gen/xai` | image backend | xAI `grok-2-image` backend |
| `mibyan-achievements` | dashboard tab | Steam-style collectible badges generated from your real Mibyan session history |
| `kanban/dashboard` | dashboard tab | Kanban board UI for the multi-agent dispatcher — tasks, comments, fan-out, board switching. See [Kanban Multi-Agent](/desktop/user-guide/features/kanban). |

Memory providers (`plugins/memory/*`) and context engines (`plugins/context_engine/*`) are listed separately on [Memory Providers](/desktop/user-guide/features/memory-providers) — they're managed through `mibyan memory` and `mibyan plugins` respectively. The full per-plugin detail for the two long-running hooks-based plugins follows.

### disk-cleanup

Auto-tracks and removes ephemeral files created during sessions — test scripts, temp outputs, cron logs, stale chrome profiles — without requiring the agent to remember to call a tool.

**How it works:**

| Hook | Behaviour |
| - | - |
| `post_tool_call` | When `write_file` / `terminal` / `patch` creates a file matching `test_*`, `tmp_*`, or `*.test.*` inside `mibyan_HOME` or `/tmp/mibyan-*`, track it silently as `test` / `temp` / `cron-output`. |
| `on_session_end` | If any test files were auto-tracked during the turn, run the safe `quick` cleanup and log a one-line summary. Stays silent otherwise. |

**Deletion rules:**

| Category | Threshold | Confirmation |
| - | - | - |
| `test` | every session end | Never |
| `temp` | >7 days since tracked | Never |
| `cron-output` | >14 days since tracked | Never |
| empty dirs under mibyan\_HOME | always | Never |
| `research` | >30 days, beyond 10 newest | Always (deep only) |
| `chrome-profile` | >14 days since tracked | Always (deep only) |
| files >500 MB | never auto | Always (deep only) |

**Slash command** — `/disk-cleanup` available in both CLI and gateway sessions:

```
/disk-cleanup status                     # breakdown + top-10 largest
/disk-cleanup dry-run                    # preview without deleting
/disk-cleanup quick                      # run safe cleanup now
/disk-cleanup deep                       # quick + list items needing confirmation
/disk-cleanup track <path> <category>    # manual tracking
/disk-cleanup forget <path>              # stop tracking (does not delete)
```

**State** — everything lives at `$mibyan_HOME/disk-cleanup/`:

| File | Contents |
| - | - |
| `tracked.json` | Tracked paths with category, size, and timestamp |
| `tracked.json.bak` | Atomic-write backup of the above |
| `cleanup.log` | Append-only audit trail of every track / skip / reject / delete |

**Safety** — cleanup only ever touches paths under `mibyan_HOME` or `/tmp/mibyan-*`. Windows mounts (`/mnt/c/...`) are rejected. Well-known top-level state dirs (`logs/`, `memories/`, `sessions/`, `cron/`, `cache/`, `skills/`, `plugins/`, `disk-cleanup/` itself) are never removed even when empty — a fresh install does not get gutted on first session end. User project trees (`workspace/`, `projects/`, `plans/`, `home/`) are never tracked or swept at all: a `test_*.py` or `tmp_*` file inside your project is source code, not scratch. `kanban/` (task attachments and workspaces) is never tracked either, and a tracked *directory* under a protected top level such as `cache/` is never removed — only the files inside it age out.

**Enabling:** `mibyan plugins enable disk-cleanup` (or check the box in `mibyan plugins`).

**Disabling again:** `mibyan plugins disable disk-cleanup`.

### security-guidance

Fast pattern-matched security warnings on file writes. When the agent's `write_file` / `patch` / `skill_manage` calls carry content matching a known-dangerous code pattern — `pickle.load`, `yaml.load` without `SafeLoader`, `eval(`, `os.system`, `subprocess(...,  shell=True)`, JS `child_process.exec`, React `dangerouslySetInnerHTML`, raw `.innerHTML =` / `.outerHTML =` / `document.write`, Node `crypto.createCipher`, AES ECB mode, TLS verification disabled, XXE-prone `xml.etree` / `minidom` parsers, `<script src="//..." >` without SRI, `torch.load` without `weights_only=True`, GitHub Actions `${{ github.event.* }}` injection — the plugin appends a `⚠️ Security guidance` block to the tool's result.

The file is still written. The model reads the warning in the next turn's tool message and can either fix the code or document why the construct is safe in this context. Pattern matching has a non-trivial false-positive rate, which is why warn (not block) is the default.

**Coverage:** 25 rules total, covering unsafe deserialization, command injection, XSS sinks, crypto footguns, XXE, supply-chain (SRI), and CI/CD workflow injection. The pattern data is a verbatim Apache-2.0 fork of [Anthropic's `claude-plugins-official`](https://github.com/anthropics/claude-plugins-official/tree/main/plugins/security-guidance/hooks) — see the plugin's `LICENSE` and `NOTICE` files for attribution.

**Modes:**

| Env var | Effect |
| - | - |
| (unset) | **warn mode** (default) — file is written, warning appended to result |
| `SECURITY_GUIDANCE_BLOCK=1` | **block mode** — write refused, warning returned as the block reason |
| `SECURITY_GUIDANCE_DISABLE=1` | kill switch — plugin loads but does nothing |

**Enabling:** `mibyan plugins enable security-guidance` (or check the box in `mibyan plugins`).

**Disabling again:** `mibyan plugins disable security-guidance`.

**What it does not do (yet):** the upstream Anthropic plugin has two more layers — an LLM diff review on each agent turn that touched files, and an agentic commit-time review that traces data flow across files. Neither is ported. The agent can already run those reviews on demand via `delegate_task`.

### observability/langfuse

Traces Mibyan turns, LLM calls, and tool invocations to [Langfuse](https://langfuse.com) — an open-source LLM observability platform. One span per turn, one generation per API call, one tool observation per tool call. Usage totals, per-type token counts, and cost estimates come out of Mibyan' canonical `agent.usage_pricing` numbers, so the Langfuse dashboard sees the same breakdown (input / output / `cache_read_input_tokens` / `cache_creation_input_tokens` / `reasoning_tokens`) that appears in `mibyan logs`.

The plugin is fail-open: no SDK installed, no credentials, or a transient Langfuse error — all turn into a silent no-op in the hook. The agent loop is never impacted.

**Setup (interactive — recommended):**

```bash theme={null}
mibyan tools          # → Langfuse Observability → Cloud or Self-Hosted
```

The wizard collects your keys, prepares the declared `langfuse` extra through PM
when needed, and enables `observability/langfuse`. Restart Mibyan and the next
turn ships a trace. If preparation fails, retry through `mibyan tools`; do not
install the SDK into the selected environment with pip.

**Setup (manual):**

For a source checkout, first follow the [PM developer workflow](/desktop/reference/package-management#developer-workflow)
with the intended Mibyan home. Use the checkout's prepared Python:

```bash theme={null}
python -c "import pm; pm.sync_venv(['langfuse'], explicit=True)"
source ./activate
python mibyan plugins enable observability/langfuse
```

Use `. .\activate.ps1` for PowerShell activation. Then put the credentials in
the active home's `.env` (`$mibyan_HOME/.env`, normally `~/.mibyan/.env`):

```bash theme={null}
mibyan_LANGFUSE_PUBLIC_KEY=pk-lf-...
mibyan_LANGFUSE_SECRET_KEY=sk-lf-...
mibyan_LANGFUSE_BASE_URL=https://cloud.langfuse.com   # or your self-hosted URL
```

**How it works:**

| Hook | Behaviour |
| - | - |
| `pre_api_request` / `pre_llm_call` | Open (or reuse) a per-turn root span "Mibyan turn". Start a `generation` child observation for this API call with serialized recent messages as input. |
| `post_api_request` / `post_llm_call` | Close the generation, attach `usage_details`, `cost_details`, `finish_reason`, assistant output + tool calls. If no tool calls and non-empty content, close the turn. |
| `pre_tool_call` | Start a `tool` child observation with sanitized `args`. |
| `post_tool_call` | Close the tool observation with sanitized `result`. `read_file` payloads get summarized (head + tail + omitted-line count) so a huge file read stays under `mibyan_LANGFUSE_MAX_CHARS`. |

Session grouping keys off the Mibyan session ID (or task ID for sub-agents) via `langfuse.propagate_attributes`, so everything in a single `mibyan chat` session lives under one Langfuse session.

**Verify:**

```bash theme={null}
mibyan plugins list                 # observability/langfuse should show "enabled"
mibyan chat -q "hello"              # check the Langfuse UI for a "Mibyan turn" trace
```

**Optional tuning** (in `.env`):

| Variable | Default | Purpose |
| - | - | - |
| `mibyan_LANGFUSE_ENV` | — | Environment tag on traces (`production`, `staging`, …) |
| `mibyan_LANGFUSE_RELEASE` | — | Release/version tag |
| `mibyan_LANGFUSE_SAMPLE_RATE` | `1.0` | Sampling rate passed to the SDK (0.0–1.0) |
| `mibyan_LANGFUSE_MAX_CHARS` | `12000` | Per-field truncation for message content / tool args / tool results |
| `mibyan_LANGFUSE_DEBUG` | `false` | Verbose plugin logging to `agent.log` |

Mibyan-prefixed and standard SDK env vars (`LANGFUSE_PUBLIC_KEY`, `LANGFUSE_SECRET_KEY`, `LANGFUSE_BASE_URL`) are both accepted — Mibyan-prefixed wins when both are set.

**Performance:** the Langfuse client is cached after the first hook call. If credentials or SDK are missing, that decision is also cached — subsequent hooks fast-return without re-checking env vars or reloading config.

**Disabling:** `mibyan plugins disable observability/langfuse`. The plugin module is still discovered, but no module code runs until you re-enable.

### NeMo Relay native integration (migration note)

NeMo Relay is no longer a bundled Mibyan plugin. Do not run `mibyan plugins enable observability/nemo_relay`; Mibyan core now owns the Relay session, turn, LLM, and tool lifecycles.

Configure Relay middleware or exporters through a standard Relay `plugins.toml`. Mibyan loads Relay's user configuration (`~/.config/nemo-relay/plugins.toml`) and then its machine-wide system configuration (`/etc/nemo-relay/plugins.toml`, or `%ProgramData%\nemo-relay\plugins.toml` on Windows). Set `mibyan_NEMO_RELAY_PLUGINS_TOML` before starting Mibyan only when you want an explicit file to replace the user configuration; the system configuration still has higher precedence. The policy is process-wide for every profile hosted by that Mibyan process. Run `mibyan doctor` to see which files apply. See the [NeMo Relay observability configuration](https://docs.nvidia.com/nemo/relay/configure-plugins/observability/about) for ATOF, ATIF, and OpenTelemetry options.

The old `mibyan_NEMO_RELAY_ATOF_*` and `mibyan_NEMO_RELAY_ATIF_*` settings no longer configure exporters. When `mibyan_NEMO_RELAY_PLUGINS_TOML` is unset, the gateway warns about remaining legacy variables and `mibyan doctor` reports them. Independently discovered Relay user or system exporters still apply.

**Automatic migration.** `mibyan update` (and `mibyan migrate relay`, or `mibyan migrate relay --all-profiles` for every profile home) converts the legacy variables into `<mibyan home>/relay-plugins.toml`, sets `mibyan_NEMO_RELAY_PLUGINS_TOML` in that profile's `.env`, and comments the legacy lines out (nothing is deleted). Under a multiplexed gateway every profile home gets its own file. The generated file is validated through Relay before it is written; this is the shape it produces (note the `type = "file"` sink discriminator — a sink without it is rejected):

```toml theme={null}
version = 1

[[components]]
kind = "observability"
enabled = true

[components.config]
version = 4
enable_full_payloads = false

[components.config.atof]
enabled = true

[[components.config.atof.sinks]]
type = "file"
output_directory = "/home/you/.mibyan/telemetry/nemo-relay/atof"
filename = "mibyan-atof.jsonl"
mode = "append"

[components.config.atif]
enabled = true
agent_name = "Mibyan"
model_name = "unknown"
output_directory = "/home/you/.mibyan/telemetry/nemo-relay/atif"
filename_template = "trajectory-{session_id}.json"

[components.config.policy]
unknown_component = "warn"
unknown_field = "warn"
unsupported_value = "error"
```

Then add `mibyan_NEMO_RELAY_PLUGINS_TOML=/home/you/.mibyan/relay-plugins.toml` to `.env` and restart the gateway.

#### Session-span segmentation (continuous sessions)

Relay exports a span when its scope closes. A continuous gateway session can keep its session span open for days even though each turn span exports normally. Optional segmentation rotates only the session scope at a turn boundary:

```yaml theme={null}
gateway:
  telemetry:
    session_segments:
      on_compaction: false  # rotate after context compaction
      max_turns: 0          # 0 = unlimited; N = turns per segment
```

| Key | Default | Behavior |
| - | -: | - |
| `on_compaction` | `false` | Rotate after compaction completes, at the next turn boundary. |
| `max_turns` | `0` | Rotate after every N completed turns; `0` disables the cap. |

Both defaults preserve one session scope for the full session. Rotated spans retain the same `session_id` and add `mibyan.session.segment` plus `mibyan.session.segment_reason` (`compaction` or `max_turns`).

### google\_meet

Lets the agent **join, transcribe, and participate in Google Meet calls** — take notes on a meeting, summarize the back-and-forth after, follow up on specific points, and (optionally) speak replies back into the call via TTS.

**What it adds:**

* A headless virtual participant that joins a Meet URL using browser automation
* Live transcription derived from Meet's own live captions (the bot never decodes the meeting audio, so no STT billing — and captions are lossy and English-biased)
* A `meet_join` / `meet_status` / `meet_transcript` / `meet_leave` / `meet_say` toolset the agent invokes to join calls, poll the live transcript, and act on what it heard
* Post-meeting artifacts (transcript, status) saved under `~/.mibyan/workspace/meetings/<meeting_id>/`

**Setup:**

```bash theme={null}
mibyan plugins enable google_meet
mibyan meet setup   # preflight: playwright, chromium, auth file
mibyan meet auth    # opens a browser to sign into Google and saves session state —
                    # needs a Google account with Meet access. Host approval may be
                    # required if the meeting enforces "only invited participants can join".
```

Usage from chat:

> "Join meet.google.com/abc-defg-hij and take notes. After the call, send me a summary with action items."

The agent kicks off the meeting join, streams the transcription back into its context as the call proceeds, and produces a structured summary when the meeting ends (or when you tell it to stop).

**Realtime mode (`mode='realtime'`) is speak-only on the audio side.** The bot's replies are synthesized by OpenAI Realtime and played into the call through a virtual microphone; what it *hears* is still the caption stream, not the meeting audio — nothing from the call is sent to the Realtime session. `meet_status` reports `micState` (`unmuted`, `unmuted_clicked` when the bot had to unmute itself after admission, or `unknown` when Meet's toggle was not found) so a silent bot can be diagnosed.

**When to use it:** recurring standups where you want a bot to transcribe + summarize for async attendees; deposition-style interviews where you want structured notes; any case where you'd otherwise need Fireflies / Otter / Grain. When you'd rather not have an AI listening in — don't enable it.

**Disabling:** `mibyan plugins disable google_meet`. Any saved transcripts stay in `~/.mibyan/workspace/meetings/` until you remove them.

### mibyan-achievements

Adds a **Steam-style achievements tab to the dashboard** — 60+ collectible, tiered badges generated from your real Mibyan session history. Tool-chain feats, debugging patterns, vibe-coding streaks, skill/memory usage, model/provider variety, lifestyle quirks (weekend and night sessions). Originally authored by [@PCinkusz](https://github.com/PCinkusz) as an external plugin; brought in-tree so it stays in lockstep with Mibyan feature changes.

**How it works:**

* Scans your entire `~/.mibyan/state.db` session history on the dashboard backend
* Per-session stats are cached by `(started_at, last_active)` fingerprint, so only new or changed sessions re-analyze on subsequent scans
* First-ever scan runs in a background thread — the dashboard never blocks waiting for it, even on databases with thousands of sessions
* Unlock state is persisted to `$mibyan_HOME/plugins/mibyan-achievements/state.json`

**Tier progression:** Copper → Silver → Gold → Diamond → Olympian. Each card exposes a "What counts" section listing the exact metric being tracked.

**Achievement states:**

| State | Meaning |
| - | - |
| Unlocked | At least one tier achieved |
| Discovered | Known achievement, progress visible, not yet earned |
| Secret | Hidden until Mibyan detects the first related signal in your history |

**API** — routes mount under `/api/plugins/mibyan-achievements/`:

| Endpoint | Purpose |
| - | - |
| `GET /achievements` | Full catalog with per-badge unlock state (returns a pending placeholder while the first cold scan is running) |
| `GET /scan-status` | State of the background scanner: `idle` / `running` / `failed`, last duration, run count |
| `GET /recent-unlocks` | Twenty most recently unlocked badges, newest first |
| `GET /sessions/{id}/badges` | Badges earned primarily in one specific session |
| `POST /rescan` | Manual synchronous rescan (blocks; use when the user clicks the rescan button) |
| `POST /reset-state` | Clear unlock history and cached snapshot |

**State files** — live under `$mibyan_HOME/plugins/mibyan-achievements/`:

| File | Contents |
| - | - |
| `state.json` | Unlock history: which badges you've earned and when. Stable across Mibyan updates. |
| `scan_snapshot.json` | Last completed scan payload (served immediately on dashboard load) |
| `scan_checkpoint.json` | Per-session stats cache keyed by fingerprint (makes warm rescans fast) |

**Performance notes:**

* Cold scan on \~8,000 sessions takes a few minutes. It runs in a background thread on first dashboard request; the UI sees a pending placeholder and polls `/scan-status`.
* **Incremental results during a cold scan** — the scanner publishes a partial snapshot every \~250 sessions so each dashboard refresh shows more badges unlocked as the scan progresses. No minute-long stare at zeros.
* Warm rescan reuses per-session stats for every session whose `started_at` + `last_active` fingerprint matches the checkpoint — completes in seconds even on large histories.
* The in-memory snapshot TTL is 120s; stale requests serve the old snapshot immediately and kick a background refresh. You never wait on a spinner just because TTL expired.

**Enabling:** Nothing to enable — `mibyan-achievements` is a dashboard-only plugin (no lifecycle hooks, no model-visible tools). It auto-registers as a tab in `mibyan dashboard` on first launch. The `plugins.enabled` config only gates lifecycle/tool plugins; dashboard plugins are discovered purely via their `dashboard/manifest.json`.

**Opting out:** Delete or rename `plugins/mibyan-achievements/dashboard/manifest.json`, or override it with a user plugin of the same name in `~/.mibyan/plugins/mibyan-achievements/` that ships no dashboard. The plugin's state files under `$mibyan_HOME/plugins/mibyan-achievements/` survive — reinstalling preserves your unlock history.

## Adding a bundled plugin

Bundled plugins are written exactly like any other Mibyan plugin — see [Build a Mibyan Plugin](/desktop/developer-guide/plugins/overview). The only differences are:

* Directory lives at `<repo>/plugins/<name>/` instead of `~/.mibyan/plugins/<name>/`
* Manifest source is reported as `bundled` in `mibyan plugins list`
* User plugins with the same name override the bundled version

A plugin is a good candidate for bundling when:

* It has no optional dependencies (or they are already in the declared `all` extra)
* The behaviour benefits most users and is opt-out rather than opt-in
* The logic ties into lifecycle hooks that the agent would otherwise have to remember to invoke
* It complements a core capability without expanding the model-visible tool surface

Counter-examples — things that should stay as user-installable plugins, not bundled: third-party integrations with API keys, niche workflows, large dependency trees, anything that would meaningfully change agent behaviour by default.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.