# How the 99 Extension System Works: A Deep Dive into Extensions.init

> Explore how Extensions.init in ThePrimeagen/99 loads, initializes, and delegates plugin operations. Understand the core of the extension system for seamless plugin integration.

- Repository: [ThePrimeagen/99](https://github.com/theprimeagen/99)
- Tags: deep-dive
- Published: 2026-02-16

---

**The `Extensions.init` function in ThePrimeagen's 99 repository acts as a thin dispatcher that loads plugin sources based on the `completion.source` configuration, initializes them globally, and delegates buffer-specific and refresh operations to the selected source module.**

The extension system in *99* keeps the core library agnostic of specific completion implementations while providing a standardized contract for plugins. When `Extensions.init` runs during startup, it detects which source to load—such as the built-in `cmp` source or custom agents—calls the source's global initialization, and sets up the workspace root for file discovery.

## How Extensions.init Loads Plugin Sources

The initialization flow begins in [`lua/99/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/init.lua) at line 85, where `Extensions.init(_99_state)` is invoked immediately after language initialization completes.

### Step 1: Source Detection via get_source

Inside [`lua/99/extensions/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/init.lua) (lines 10-19), the private helper `get_source(completion)` reads `_99_state.completion.source` to determine which module to load. If the source string equals `"cmp"`, the function requires `99.extensions.cmp` and returns that module table.

```lua
-- Simplified logic from lua/99/extensions/init.lua
local function get_source(completion)
    if completion.source == "cmp" then
        return require("99.extensions.cmp")
    end
    -- Additional sources can be added here
end

```

### Step 2: Global Initialization

Once a source module is identified, `Extensions.init` executes `source.init(_99_state)` at lines 21-30 of [`lua/99/extensions/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/init.lua). For the built-in CMP source, this registration happens in [`lua/99/extensions/cmp.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/cmp.lua) (lines 90-118), where the code creates a singleton `CmpSource` object, registers it with Neovim's CMP, and sets up file-search rules and agent-based completions.

### Step 3: Project Root Capture

Immediately after source initialization, `Extensions.capture_project_root()` determines the workspace root by checking for a git repository or falling back to the current working directory. This value is stored in the `Files` module to anchor all subsequent file discovery operations (lines 31-35 of [`lua/99/extensions/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/init.lua)).

## Buffer-Level and Refresh Operations

The extension system delegates per-buffer configuration and dynamic updates to the selected source through two additional entry points.

### Per-Buffer Setup with setup_buffer

When a new buffer opens, `Extensions.setup_buffer(_99_state)` is called (typically from the UI layer), which forwards to `source.init_for_buffer(_99_state)` at lines 37-44 of [`lua/99/extensions/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/init.lua). In the CMP implementation ([`lua/99/extensions/cmp.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/cmp.lua), lines 66-82), this sets the buffer's `filetype` to `99prompt` and registers a buffer-local CMP source, ensuring completion contexts remain isolated per buffer.

### Dynamic Configuration Refresh

Whenever the user modifies configuration—such as updating file exclude patterns—the `Files.setup(new_config)` function updates the internal state, followed by `Extensions.refresh(_99_state)` at lines 46-53 of [`lua/99/extensions/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/init.lua). This delegates to `source.refresh_state(_99_state)`, which for the CMP source (lines 120-126 of [`lua/99/extensions/cmp.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/cmp.lua)) re-registers file- and agent-based completions to reflect the new filtering rules without requiring a full editor restart.

## The CMP Source Implementation

The built-in CMP source demonstrates the contract expected by `Extensions.init`. Located at [`lua/99/extensions/cmp.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/cmp.lua), it exports three functions:

- **`init(_99)`**: Registers the global CMP source and initializes file-search and agent subsystems (lines 90-118).
- **`init_for_buffer(_99)`**: Configures buffer-local completion contexts (lines 66-82).
- **`refresh_state(_99)`**: Updates completion providers when configuration changes (lines 120-126).

This implementation relies on [`lua/99/extensions/files/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/files/init.lua) for file discovery and filtering, and can be extended to include agent-based sources via [`lua/99/extensions/agents/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/agents/init.lua).

## Creating Custom Extension Sources

To add a new extension source to *99*:

1. **Create a module** at `lua/99/extensions/<name>.lua` that returns a table implementing:
   - `init(_99)` for global setup,
   - `init_for_buffer(_99)` for per-buffer configuration,
   - `refresh_state(_99)` for dynamic updates.

2. **Expose the source name** via the `completion.source` configuration option (e.g., `"my_source"`).

3. **Register the dispatcher** by updating the `get_source` function in [`lua/99/extensions/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/init.lua) to require your new module when the source string matches.

Because `Extensions` only depends on these three function signatures, any plugin adhering to this contract can be hot-plugged without modifying the core *99* codebase.

## Summary

- **`Extensions.init`** serves as the central dispatcher that loads plugin sources based on the `completion.source` configuration value.
- The system uses a **three-phase lifecycle**: global initialization (`init`), per-buffer setup (`setup_buffer`), and dynamic refresh (`refresh`).
- **Source detection** occurs in `get_source` within [`lua/99/extensions/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/init.lua), which maps strings like `"cmp"` to concrete Lua modules.
- The **CMP source** ([`lua/99/extensions/cmp.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/cmp.lua)) demonstrates the expected contract, implementing all three lifecycle functions to register completion providers with Neovim's CMP.
- **Custom sources** can be added by creating a module with the three required functions and registering it in the dispatcher, keeping the core library agnostic of specific implementations.

## Frequently Asked Questions

### What is the purpose of Extensions.init in the 99 plugin?

`Extensions.init` acts as the bootstrap mechanism for the 99 extension system. It detects which completion source the user has configured (such as `"cmp"` for the built-in CMP integration), loads the corresponding Lua module, and executes that module's global initialization function to set up completion providers, file search rules, and project root detection.

### How does 99 handle per-buffer completion configuration?

After global initialization, 99 delegates buffer-local setup to `Extensions.setup_buffer`, which forwards to the selected source's `init_for_buffer` function. For the CMP source, this sets the buffer's filetype to `99prompt` and registers a buffer-local CMP source, ensuring that completion contexts remain isolated and properly scoped to individual buffers.

### Can I create a custom completion source for 99?

Yes, you can create a custom source by implementing a Lua module at `lua/99/extensions/<your_source>.lua` that exports three functions: `init(_99)` for global setup, `init_for_buffer(_99)` for per-buffer configuration, and `refresh_state(_99)` for handling configuration changes. You must then register your source name in the `get_source` function within [`lua/99/extensions/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/init.lua) to map your source string to the new module.

### What triggers a refresh in the 99 extension system?

A refresh is triggered when the user modifies configuration values that affect completion behavior, such as updating file exclude patterns or changing search directories. The `Extensions.refresh` function delegates to the active source's `refresh_state` method, which for the built-in CMP source re-registers file- and agent-based completions to reflect the new filtering rules without requiring a full editor restart.