# How the 99 Completion System Handles #rules and @file References

> Discover how the 99 completion system efficiently handles #rules and @file references. Learn about its provider-based architecture and token validation for seamless markdown resolution.

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

---

**The 99 completion system processes `#rules` and `@file` references through a provider-based architecture where trigger characters (`#` and `@`) activate specialized completion providers that validate tokens against project rules or filesystem paths and resolve them into markdown content before prompt submission.**

The 99 plugin by ThePrimeagen implements a sophisticated completion framework that transforms shorthand references into full contextual content. Understanding how the 99 completion system resolves these tokens is essential for customizing AI interactions and extending the plugin's functionality.

## Core Completion Engine Architecture

The central completion engine in [`lua/99/extensions/completions.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/completions.lua) orchestrates all token resolution. It maintains a registry of providers and exposes a unified parsing interface that the rest of the application consumes.

### Provider Registration and Trigger Detection

The engine uses a registration pattern to support extensible token types. Each provider registers itself via `M.register(provider)`, which stores the provider in a local table indexed by trigger character.

```lua
-- From completions.lua
M.register = function(provider)
  providers[provider.trigger] = provider
end

```

The `M.get_trigger_characters()` function exposes active triggers (`#` and `@`) to the completion UI, while `M.get_keyword_pattern()` returns regex patterns like `#%S+` and `@%S+` for fuzzy matching.

### Parsing and Token Resolution

When processing a prompt, `M.parse(prompt_text)` iterates through registered providers to identify and resolve tokens:

1. **Pattern matching** – Builds a regex from the provider's trigger character
2. **Token validation** – Calls `provider.is_valid(token)` to verify existence
3. **Content resolution** – Invokes `provider.resolve(token)` to fetch markdown content

Source: **[completions.lua – parse function](https://github.com/ThePrimeagen/99/blob/master/lua/99/extensions/completions.lua#L46-L66)**

## Rule Provider Implementation (#rules)

The `#rules` provider, defined in [`lua/99/extensions/agents/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/agents/init.lua), handles references to custom rule files that guide AI behavior.

### Provider Structure and Validation

The `M.completion_provider(_99)` function returns a provider table configured for rule resolution:

```lua
return {
  trigger = "#",
  name = "rules",
  get_items = function() ... end,
  is_valid = function(token) 
    return M.is_rule(_99.rules, token) 
  end,
  resolve = function(token) ... end,
}

```

The `is_rule` helper scans `_99.rules.custom` – the list of directories containing user-defined rule files – to verify that the referenced rule exists.

### Content Resolution

When a rule token is validated, the `resolve` function:
1. Locates the rule file in the custom rules directories
2. Reads the file content
3. Wraps it in a markdown code block
4. Returns the formatted string for prompt insertion

Source: **[agents init – completion_provider](https://github.com/ThePrimeagen/99/blob/master/lua/99/extensions/agents/init.lua#L29-L62)**

## File Provider Implementation (@file)

The `@file` provider in [`lua/99/extensions/files/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/files/init.lua) enables inline references to source code files, allowing the AI to see implementation details without manual copy-pasting.

### File Discovery and Caching

The provider maintains a cached index of project files through `M.discover_files()`:

- Walks the project root directory
- Respects exclusion patterns (e.g., `node_modules`, `.git`)
- Enforces file size limits to prevent token overflow
- Caches results for performance

### Token Validation and Resolution

The completion provider structure mirrors the rules provider but uses file-specific validation:

```lua
return {
  trigger = "@",
  name = "files",
  get_items = function() ... end,
  is_valid = function(token) 
    return M.is_project_file(token) 
  end,
  resolve = function(token) ... end,
}

```

The `is_project_file` function checks the discovered file cache for exact path matches or filename matches. Upon resolution, `resolve` reads the file content, detects the language from the file extension, and returns a fenced code block.

Source: **[files init – completion_provider](https://github.com/ThePrimeagen/99/blob/master/lua/99/extensions/files/init.lua#L57-L96)**

## Neovim CMP Integration

The 99 completion system bridges to Neovim's native completion UI through [`lua/99/extensions/cmp.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/cmp.lua), which implements the `nvim-cmp` source interface.

The CMP source delegates trigger character detection to the core engine:

```lua
function CmpSource.get_trigger_characters()
  return Completions.get_trigger_characters()
end

```

This ensures that typing `#` or `@` automatically invokes the completion menu without hardcoding characters in the CMP layer. The `get_completions` method similarly delegates to the engine's parsing logic, converting 99 completion items into the format expected by `nvim-cmp`.

Source: **[cmp.lua – trigger characters](https://github.com/ThePrimeagen/99/blob/master/lua/99/extensions/cmp.lua#L30-L33)**

## End-to-End Workflow Example

Consider a user working with the 99 plugin who types the following prompt:

```lua
-- User input:
local prompt = "Explain the core idea of #my_rule and show its implementation in @src/main.lua"

```

The completion system processes this through the following pipeline:

1. **Trigger Detection**: The UI identifies `#` and `@` as trigger characters via `Completions.get_trigger_characters()`

2. **Token Parsing**: `Completions.parse(prompt)` extracts `#my_rule` and `@src/main.lua`

3. **Validation**: 
   - The agents provider confirms `#my_rule` exists in `_99.rules.custom`
   - The files provider verifies `@src/main.lua` exists in the project cache

4. **Resolution**:
   - Rule content is wrapped in markdown
   - File content is read and fenced with ```lua

5. **Final Prompt Assembly**:

```lua
local final_prompt = [[
Explain the core idea of <content of my_rule>
and show its implementation in 

```lua
-- src/main.lua
local function foo() … end

```

]]

```

## Summary

- The **99 completion system** uses a provider-based architecture in [`lua/99/extensions/completions.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/completions.lua) to handle special token references.
- **`#rules`** are resolved by the agents provider ([`lua/99/extensions/agents/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/agents/init.lua)), which validates tokens against custom rule directories and returns markdown-wrapped content.
- **`@file`** references are handled by the files provider ([`lua/99/extensions/files/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/files/init.lua)), which maintains a cached project file index, validates paths, and returns fenced code blocks with language detection.
- The system integrates with **nvim-cmp** through [`lua/99/extensions/cmp.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/cmp.lua), exposing trigger characters dynamically based on registered providers.
- New token types can be added by implementing the provider interface and registering with `Completions.register()`.

## Frequently Asked Questions

### How does the 99 completion system detect when to show completion suggestions?

The system exposes trigger characters through `Completions.get_trigger_characters()`, which aggregates triggers from all registered providers. When the user types `#` or `@`, the nvim-cmp integration ([`lua/99/extensions/cmp.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/cmp.lua)) detects these characters and invokes the completion menu automatically.

### What happens if I reference a rule or file that doesn't exist?

The provider's `is_valid` function returns `false` for non-existent tokens. During the parsing phase in `Completions.parse()`, invalid tokens are skipped and not included in the final resolved prompt. The UI typically filters these out during completion suggestion display.

### Can I add custom trigger characters beyond # and @?

Yes. The provider architecture supports arbitrary trigger characters. You can create a new provider module implementing the `trigger`, `is_valid`, and `resolve` interface methods, then register it via `Completions.register(provider)` in [`lua/99/extensions/completions.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/completions.lua). The CMP integration will automatically pick up the new trigger.

### How does the file provider handle large files?

The files provider ([`lua/99/extensions/files/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/extensions/files/init.lua)) enforces size limits during the discovery phase in `M.discover_files()`. When resolving a token, `M.resolve()` checks the file size against configured limits before reading. Files exceeding the limit are either truncated or excluded from resolution to prevent context window overflow.