# How 99 Handles AGENT.md File Discovery and Injection into AI Context

> Discover how the 99 Neovim plugin finds and injects AGENT.md file content into AI context for LLM requests. Learn about its automatic discovery process.

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

---

**The 99 Neovim plugin automatically discovers [`AGENT.md`](https://github.com/ThePrimeagen/99/blob/main/AGENT.md) files by walking up the directory tree from the current buffer and injects their contents into the AI prompt context before sending requests to the LLM.**

ThePrimeagen's `99` plugin treats specially named markdown files as persistent context that should accompany every AI request. By default, the plugin searches for [`AGENT.md`](https://github.com/ThePrimeagen/99/blob/main/AGENT.md) files using an upward directory traversal algorithm, ensuring that project-specific instructions follow the developer regardless of which nested file they are currently editing.

## Configuring AGENT.md Discovery in 99

The plugin stores the list of context filenames in the **`md_files`** configuration option. According to the source code in [`lua/99/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/init.lua) (lines 86-94), the default setup includes a single entry:

```lua
require("99").setup({
  md_files = { "AGENT.md" },
})

```

You can customize this list during initialization to include additional markdown files. The plugin accepts any filename or relative path, allowing you to maintain separate context documents for different aspects of your codebase.

## The AGENT.md File Discovery Process

When you trigger an AI request, `99` creates a `RequestContext` object via `RequestContext.from_current_buffer`. During this initialization (implemented in [`lua/99/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/init.lua), lines 575-605), the current `md_files` configuration is copied into the request's `md_file_names` field.

The actual discovery logic resides in [`lua/99/request-context.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/request-context.lua) (lines 82-108) within the `_read_md_files` method. The algorithm performs the following steps:

1. **Identify boundaries**: Determines the current working directory (`cwd`) and the directory containing the active buffer (`dir`).
2. **Traverse upward**: Uses a `while` loop to walk from the buffer's directory toward the project root, stopping when it reaches the `cwd`.
3. **Check each directory**: For every level in the hierarchy, it checks for the existence of each filename listed in `md_file_names`.
4. **Collect contents**: When a match is found, the file is opened, read entirely (`*a` pattern), and its contents stored.

```lua
-- Simplified excerpt from lua/99/request-context.lua
function RequestContext:_read_md_files()
  local cwd = vim.uv.cwd()
  local dir = vim.fn.fnamemodify(self.full_path, ":h")

  while dir:find(cwd, 1, true) == 1 do
    for _, md_file_name in ipairs(self.md_file_names) do
      local md_path = dir .. "/" .. md_file_name
      local file = io.open(md_path, "r")
      if file then
        local content = file:read("*a")
        file:close()
        table.insert(self.ai_context, content)
      end
    end
    if dir == cwd then break end
    dir = vim.fn.fnamemodify(dir, ":h")
  end
end

```

## How 99 Injects AGENT.md Content into AI Context

Once the discovery phase completes, the collected content resides in the `ai_context` table of the request object. The injection occurs during the finalization stage in `RequestContext:finalize` (lines 136-146 of [`lua/99/request-context.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/request-context.lua)).

The plugin concatenates all strings in `ai_context` and includes them as part of the complete prompt sent to the LLM provider. This ensures that instructions, coding standards, or project context defined in [`AGENT.md`](https://github.com/ThePrimeagen/99/blob/main/AGENT.md) files are prepended or appended to the user's actual query, giving the AI persistent awareness of the project's requirements.

## Customizing Markdown Context Files

You can extend beyond the default [`AGENT.md`](https://github.com/ThePrimeagen/99/blob/main/AGENT.md) to maintain multiple context documents. For example, you might separate architectural decisions from coding standards:

```lua
require("99").setup({
  md_files = { 
    "AGENT.md",           -- General project context
    "ARCHITECTURE.md",    -- System design decisions
    ".cursorrules",       -- Coding standards
  },
})

```

The plugin discovers all specified files at each directory level, merging their contents in the order found during the upward traversal. Files closer to the buffer's directory take precedence in the discovery order, though all discovered files are included in the final context.

## Summary

- **Default Configuration**: The `99` plugin automatically searches for [`AGENT.md`](https://github.com/ThePrimeagen/99/blob/main/AGENT.md) files via the `md_files` option, which defaults to `{"AGENT.md"}` in [`lua/99/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/init.lua).
- **Discovery Algorithm**: The `_read_md_files` method in [`lua/99/request-context.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/request-context.lua) walks upward from the current buffer's directory to the project root, checking each level for configured markdown files.
- **Context Injection**: Discovered file contents are stored in the `ai_context` table and concatenated into the final prompt during `RequestContext:finalize`, ensuring persistent project context accompanies every AI request.
- **Customization**: Users can override `md_files` in the setup configuration to include additional context documents like [`README.md`](https://github.com/ThePrimeagen/99/blob/main/README.md) or custom standards files.

## Frequently Asked Questions

### How does 99 decide which AGENT.md file to use when multiple exist in the project hierarchy?

The plugin discovers **all** [`AGENT.md`](https://github.com/ThePrimeagen/99/blob/main/AGENT.md) files found during the upward directory traversal from the current buffer to the project root. According to the implementation in [`lua/99/request-context.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/request-context.lua), each discovered file's contents are appended to the `ai_context` table. This means nested projects can have specific instructions at lower levels and general instructions at higher levels, with all contexts being included in the final prompt.

### Can I disable AGENT.md discovery entirely in 99?

Yes, you can disable the feature by setting the `md_files` option to an empty table in your setup configuration. In [`lua/99/init.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/init.lua), the default value is `{"AGENT.md"}`, but passing `md_files = {}` prevents the `_read_md_files` method from finding any files to inject, effectively disabling the automatic context injection while keeping other plugin features active.

### What happens if an AGENT.md file is malformed or contains binary data?

The plugin uses Lua's `io.open` with the `"r"` (read) mode and `file:read("*a")` to read the entire file contents as text, as seen in [`lua/99/request-context.lua`](https://github.com/ThePrimeagen/99/blob/main/lua/99/request-context.lua). If the file contains binary data or invalid UTF-8 sequences, the behavior depends on how the subsequent prompt construction and HTTP client handle the data. However, the plugin itself does not validate or sanitize the content—it simply reads and appends the raw text to the `ai_context` table.

### Does 99 watch AGENT.md files for changes or cache their contents?

Based on the source code analysis, the plugin does not implement file watching or caching for [`AGENT.md`](https://github.com/ThePrimeagen/99/blob/main/AGENT.md) files. The `_read_md_files` method reads the files synchronously during the request finalization phase (`RequestContext:finalize`) each time a request is created. This means changes to [`AGENT.md`](https://github.com/ThePrimeagen/99/blob/main/AGENT.md) files take effect immediately on the next AI request without requiring a Neovim restart, but the plugin incurs the I/O cost of reading the files on every request.