How 99 Builds the Request Context for AI Providers

99 constructs a comprehensive RequestContext in three distinct stages—initializing from the current Neovim buffer, enriching it with code references and markdown documentation, and serializing the result into a prompt file—before dispatching to providers like OpenCodeProvider or ClaudeCodeProvider.

The 99 plugin for Neovim orchestrates AI-assisted coding workflows by meticulously assembling a request context that captures your complete editing environment. Understanding how 99 builds this context reveals the mechanism by which it gathers buffer metadata, project documentation, and code selections to generate deterministic, richly-contextualized AI prompts.

Stage 1: Initializing from the Current Buffer

The construction process begins in lua/99/request-context.lua with the RequestContext.from_current_buffer method (lines 26‑53). This static factory method captures the essential metadata from your current editing session:

  • Buffer identification: The current buffer number via vim.api.nvim_get_current_buf()
  • File path: Absolute path resolution through vim.api.nvim_buf_get_name()
  • Filetype normalization: Conversion of compound types like typescriptreact to typescript
  • Temporary file generation: A unique scratch file created via utils.random_file() for provider output
  • Model selection: The AI model specified in the global state
  • Documentation index: The set of markdown filenames (.md) configured by the user
local ctx = require("99.request-context").from_current_buffer(state, request_id)

At this stage, the context object contains the structural foundation but lacks the actual content references and documentation text that will guide the AI model.

Stage 2: Populating the AI Context

Once initialized, the context undergoes enrichment through three primary mechanisms defined in lua/99/request-context.lua: reference aggregation, markdown ingestion, and range extraction.

Adding Code References

The add_references method (lines 74‑80) appends raw content extracted from Treesitter queries or LSP symbols to the ai_context array. These references provide the AI with specific code definitions relevant to the current operation:

-- refs is an array of {content = "..."} tables from Treesitter analysis
ctx:add_references(refs)

Ingesting Markdown Documentation

The _read_md_files method (lines 82‑108) implements a lazy directory traversal that searches for user-configured markdown files. Starting from the current file's directory and walking upward to the project root (vim.uv.cwd()), it reads the contents of each discovered .md file and appends them to the context:

  • Searches for files specified in state.md_files
  • Traverses parent directories until reaching the working directory root
  • Reads file contents and adds them to the ai_context array

Capturing Visual Selections

When operating on a specific code range, the context captures precise location data. If ctx.range is set (typically from a visual selection), the finalize method incorporates:

  • File location tags: XML-like markers from prompt-settings.lua indicating the file path and line range
  • Range text: The raw selected text extracted from the buffer

Stage 3: Serializing and Handing Off to the Provider

The final stage transforms the enriched context into a concrete prompt file and dispatches it to the AI provider. This orchestration occurs in lua/99/request/init.lua within the Request:start method (lines 19‑32).

Finalizing the Context

The finalize method (lines 136‑146 in request-context.lua) performs the last assembly steps:

  1. Appends the MustObey block: Inserts instructions telling the model where to write its output (the temporary file location)
  2. Concatenates all context entries: Joins the ai_context array into the final prompt structure

Writing the Prompt File

The Request class writes the serialized context to a temporary file with the -prompt suffix:

local prompt = table.concat(self._content, "\n")
-- Written to <temp_file>-prompt

Provider Dispatch

Finally, the request invokes the selected provider's make_request method. By default, 99 uses OpenCodeProvider, though ClaudeCodeProvider and others are available:

provider:make_request(prompt, self, observer)

The provider reads the prompt file, executes the AI model, and streams responses back through the observer callbacks (on_start, on_stdout, on_stderr, on_complete).

Key Files in the Context Pipeline

File Role
lua/99/request-context.lua Defines RequestContext class with from_current_buffer, add_references, _read_md_files, and finalize methods.
lua/99/request/init.lua Orchestrates the request lifecycle via Request:new() and Request:start(), handling serialization and provider dispatch.
lua/99/prompt-settings.lua Supplies XML-style tags (<Location>, <TEMP_FILE>, etc.) embedded into the context for model instruction.
lua/99/providers.lua Defines the provider interface; implementations like OpenCodeProvider consume the generated prompt files.
lua/99/utils.lua Provides random_file() utility for generating unique temporary file paths used throughout the context.

Summary

  • Three-stage pipeline: 99 builds request context through initialization (from_current_buffer), enrichment (add_references, _read_md_files), and serialization (finalize).
  • Comprehensive metadata: The context captures buffer state, file paths, normalized filetypes, project documentation, code references, and visual selection ranges.
  • Deterministic output: The finalize method ensures the model receives explicit instructions via the MustObey block, directing output to a specific temporary file location.
  • Provider agnostic: The serialized prompt is written to disk before make_request dispatches to any provider (OpenCodeProvider, ClaudeCodeProvider, etc.), ensuring reproducible AI interactions.

Frequently Asked Questions

What information does 99 capture from the current buffer?

99 captures the buffer number, absolute file path, normalized filetype (converting variants like typescriptreact to typescript), and the specific AI model configured in your state. This occurs in RequestContext.from_current_buffer within lua/99/request-context.lua (lines 26‑53), which also generates a unique temporary file path for the provider's output.

How does 99 handle project documentation?

The plugin lazily ingests markdown files configured in state.md_files through the _read_md_files method (lines 82‑108 in lua/99/request-context.lua). This function traverses upward from the current file's directory to the project root (vim.uv.cwd()), reading the contents of any discovered .md files and appending them to the ai_context array for the model to reference.

What happens if I have a visual selection active?

When a visual range is present, 99 appends precise location metadata and the raw selected text to the context. During finalize (lines 136‑146 in lua/99/request-context.lua), the system inserts XML-style tags from prompt-settings.lua indicating the file location and range boundaries, followed by the actual text content of the selection, ensuring the model understands exactly which code you're referencing.

Which AI providers does 99 support?

99 supports multiple providers through a common interface defined in lua/99/providers.lua. The default implementation is OpenCodeProvider, though ClaudeCodeProvider and others are available. Regardless of the provider, the interaction follows the same pattern: the Request:start method writes the serialized context to a temporary file, then calls provider:make_request(prompt, self, observer) to execute the AI command and stream results back through observer callbacks.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →