[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-73383":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":15,"forks30d":15,"starsTrendScore":19,"compositeScore":20,"rankGlobal":9,"rankLanguage":9,"license":9,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":23,"hasPages":21,"topics":24,"createdAt":9,"pushedAt":9,"updatedAt":25,"readmeContent":26,"aiSummary":27,"trendingCount":15,"starSnapshotCount":15,"syncStatus":28,"lastSyncTime":29,"discoverSource":30},73383,"99","ThePrimeagen\u002F99","ThePrimeagen","Neovim AI agent done right",null,"Lua",4685,248,44,9,0,10,14,84,30,29.19,false,"master",true,[],"2026-06-12 02:03:12","# 99\nThe AI client that Neovim deserves, built by those that still enjoy to code.\n\n## IF YOU ARE HERE FROM [THE YT VIDEO](https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=ws9zR-UzwTE)\nSo many things have changed.  So please be careful!\n\n## WARNING :: API CHANGES RIGHT NOW\nIt will happen that apis will disapear or be changed.  Sorry, this is an BETA product.\n\n## Project Direction\nThis repo is meant to be my exploration grounds for using AI mixed with tradcoding.\n\nI believe that hand coding is still very important and the best products i know\nof today still do that (see opencode vs claude code)\n\n## Warning\n1. Prompts are temporary right now. they could be massively improved\n2. Officially in beta, but api can still change.  unlikely at this point\n\n# 99\nThe AI Neovim experience\n\n## _99\n99 is an agentic workflow that is meant to meld the current programmers ability\nwith the amazing powers of LLMs.  Instead of being a replacement, its meant to\naugment the programmer.\n\nAs of now, the direction of 99 is to progress into agentic programming and surfacing\nof information.  In the beginning and the original youtube video was about replacing\nspecific pieces of code.  The more i use 99 the more i realize the better use is\nthrough `search` and `work`\n\n### Basic Setup\n```lua\n\t{\n\t\t\"ThePrimeagen\u002F99\",\n\t\tconfig = function()\n\t\t\tlocal _99 = require(\"99\")\n\n            -- For logging that is to a file if you wish to trace through requests\n            -- for reporting bugs, i would not rely on this, but instead the provided\n            -- logging mechanisms within 99.  This is for more debugging purposes\n            local cwd = vim.uv.cwd()\n            local basename = vim.fs.basename(cwd)\n\t\t\t_99.setup({\n                -- provider = _99.Providers.ClaudeCodeProvider,  -- default: OpenCodeProvider\n\t\t\t\tlogger = {\n\t\t\t\t\tlevel = _99.DEBUG,\n\t\t\t\t\tpath = \"\u002Ftmp\u002F\" .. basename .. \".99.debug\",\n\t\t\t\t\tprint_on_error = true,\n\t\t\t\t},\n                -- When setting this to something that is not inside the CWD tools\n                -- such as claude code or opencode will have permission issues\n                -- and generation will fail refer to tool documentation to resolve\n                -- https:\u002F\u002Fopencode.ai\u002Fdocs\u002Fpermissions\u002F#external-directories\n                -- https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fpermissions#read-and-edit\n                tmp_dir = \".\u002Ftmp\",\n\n                --- Completions: #rules and @files in the prompt buffer\n                completion = {\n                    -- I am going to disable these until i understand the\n                    -- problem better.  Inside of cursor rules there is also\n                    -- application rules, which means i need to apply these\n                    -- differently\n                    -- cursor_rules = \"\u003Ccustom path to cursor rules>\"\n\n                    --- A list of folders where you have your own SKILL.md\n                    --- Expected format:\n                    --- \u002Fpath\u002Fto\u002Fdir\u002F\u003Cskill_name>\u002FSKILL.md\n                    ---\n                    --- Example:\n                    --- Input Path:\n                    --- \"scratch\u002Fcustom_rules\u002F\"\n                    ---\n                    --- Output Rules:\n                    --- {path = \"scratch\u002Fcustom_rules\u002Fvim\u002FSKILL.md\", name = \"vim\"},\n                    --- ... the other rules in that dir ...\n                    ---\n                    custom_rules = {\n                      \"scratch\u002Fcustom_rules\u002F\",\n                    },\n\n                    --- Configure @file completion (all fields optional, sensible defaults)\n                    files = {\n                        -- enabled = true,\n                        -- max_file_size = 102400,     -- bytes, skip files larger than this\n                        -- max_files = 5000,            -- cap on total discovered files\n                        -- exclude = { \".env\", \".env.*\", \"node_modules\", \".git\", ... },\n                    },\n                    --- File Discovery:\n                    --- - In git repos: Uses `git ls-files` which automatically respects .gitignore\n                    --- - Non-git repos: Falls back to filesystem scanning with manual excludes\n                    --- - Both methods apply the configured `exclude` list on top of gitignore\n\n                    --- What autocomplete engine to use. Defaults to native (built-in) if not specified.\n                    source = \"native\", -- \"native\" (default), \"cmp\", or \"blink\"\n                },\n\n                --- WARNING: if you change cwd then this is likely broken\n                --- ill likely fix this in a later change\n                ---\n                --- md_files is a list of files to look for and auto add based on the location\n                --- of the originating request.  That means if you are at \u002Ffoo\u002Fbar\u002Fbaz.lua\n                --- the system will automagically look for:\n                --- \u002Ffoo\u002Fbar\u002FAGENT.md\n                --- \u002Ffoo\u002FAGENT.md\n                --- assuming that \u002Ffoo is project root (based on cwd)\n\t\t\t\tmd_files = {\n\t\t\t\t\t\"AGENT.md\",\n\t\t\t\t},\n\t\t\t})\n\n            -- take extra note that i have visual selection only in v mode\n            -- technically whatever your last visual selection is, will be used\n            -- so i have this set to visual mode so i dont screw up and use an\n            -- old visual selection\n            --\n            -- likely ill add a mode check and assert on required visual mode\n            -- so just prepare for it now\n\t\t\tvim.keymap.set(\"v\", \"\u003Cleader>9v\", function()\n\t\t\t\t_99.visual()\n\t\t\tend)\n\n            --- if you have a request you dont want to make any changes, just cancel it\n\t\t\tvim.keymap.set(\"n\", \"\u003Cleader>9x\", function()\n\t\t\t\t_99.stop_all_requests()\n\t\t\tend)\n\n\t\t\tvim.keymap.set(\"n\", \"\u003Cleader>9s\", function()\n\t\t\t\t_99.search()\n\t\t\tend)\n\t\tend,\n\t},\n```\n\n### Usage\nI would highly recommend trying out `search` as its the direction the library is going\n\n```lua\n_99.search()\n```\n\nSee search for more details\n\n### Description\n| Name | Type | Default Value |\n| --- | --- | --- |\n| `setup` | `fun(opts?: _99.Options): nil` | - |\n| `search` | `fun(opts: _99.ops.SearchOpts): _99.TraceID` | - |\n| `vibe` | `fun(opts?: _99.ops.Opts): _99.TraceID \\| nil` | - |\n| `open` | `fun(): nil` | - |\n| `visual` | `fun(opts: _99.ops.Opts): _99.TraceID` | - |\n| `view_logs` | `fun(): nil` | - |\n| `stop_all_requests` | `fun(): nil` | - |\n| `clear_previous_requests` | `fun(): nil` | - |\n| `Extensions` | `_99.Extensions` | - |\n\n### API\n\n#### setup\nSets up _99.  Must be called for this library to work.  This is how we setup\nin flight request spinners, set default values, get completion to work the\nway you want it to.\n\n#### search\nPerforms a search across your project with the prompt you provide and return out a list of\nlocations with notes that will be put into your quick fix list.\n\n#### vibe\nNo description.\n\n#### open\nOpens a selection window for you to select the last interaction to open\nand display its contents in a way that makes sense for its type.  For\nsearch and vibe, it will open the qfix window.  For tutorial, it will open\nthe tutorial window.\n\n#### visual\ntakes your current selection and sends that along with the prompt provided and replaces\nyour visual selection with the results\n\n#### view_logs\nviews the most recent logs and setups the machine to view older and new logs\nthis is still pretty rough and will change in the near future\n\n#### stop_all_requests\nstops all in flight requests.  this means that the underlying process will\nbe killed (OpenCode) and any result will be discared\n\n#### clear_previous_requests\nclears all previous search and visual operations\n\n#### Extensions\ncheck out Worker for cool abstraction on search and vibe\n\n## _99.Extensions.Worker\nA persistent way to keep track of work.\n\nthis will likely be where the most change and focus goes into.  I would like\nto take this into worktree territory and be able to swap between stuff super\nslick.\n\nUntil then, it is going to be a single bit of work that you can provide\nthe description and then use search to find what is left that needs to be done.\n\n### Description\n| Name | Type | Default Value |\n| --- | --- | --- |\n| `set_work` | `fun(opts?: _99.WorkOpts): nil` | - |\n| `search` | `fun(): nil` | - |\n\n### API\n\n#### set_work\nwill set the work for the project.  If opts provide a description then no\ninput capture of work description will be required\n\n#### search\nwill use _99.search to find what is left to be done for this work item to be\nconsidered done\n\n## _99.Options\nNo description.\n\n### Description\n| Name | Type | Default Value |\n| --- | --- | --- |\n| `logger` | `_99.Logger.Options \\| nil` | - |\n| `model` | `string \\| nil` | - |\n| `in_flight_options` | `_99.InFlight.Opts \\| nil` | - |\n| `md_files` | `string[] \\| nil` | - |\n| `provider` | `_99.Providers.BaseProvider \\| nil` | - |\n| `display_errors` | `boolean \\| nil` | - |\n| `auto_add_skills` | `boolean \\| nil` | - |\n| `completion` | `_99.Completion \\| nil` | - |\n| `tmp_dir` | `string \\| nil` | - |\n\n### API\n\n#### logger\nNo description.\n\n#### model\nNo description.\n\n#### in_flight_options\nNo description.\n\n#### md_files\nNo description.\n\n#### provider\nNo description.\n\n#### display_errors\nNo description.\n\n#### auto_add_skills\nNo description.\n\n#### completion\nNo description.\n\n#### tmp_dir\nNo description.\n\n## _99.ops.Opts\nThe options that are used throughout all the interations with 99.  This\nincludes search, visual, and others\n\n### Description\n| Name | Type | Default Value |\n| --- | --- | --- |\n| `additional_prompt` | `string \\| nil` | - |\n| `additional_rules` | `_99.Agents.Rule[] \\| nil` | - |\n\n### API\n\n#### additional_prompt\nby providing `additional_prompt` you will not be required to provide a prompt.\nthis allows you to define actions based on remaps\n\n```lua\nremap(\"n\", \"\u003Cleader>9d\", function()\n  --- this function could be used to auto debug your project\n  _99.search({\n    additional_prompt = [[\nrun `make test` and debug the test failures and provide me a comprehensive set of steps where\nthe tests are breaking ]]\n  })\nend)\n```\n\nThis would kick off a search job that will run your tests in the background.\nthe resulting failures would be diagnosed and search results would be transfered\ninto a quick fix list.\n\n#### additional_rules\ncan be used to provide extra args.  If you have a skill called \"cloudflare\" you could\nprovide the rule for cloudflare and its context will be injected into your request\n\n## _99.ops.SearchOpts\nSee `_99.opts.Opts` for more information.\n\nThere are no properties yet.  But i would like to tweek some behavior based on opts\n\n### Description\n| Name | Type | Default Value |\n| --- | --- | --- |\n| - | - | - |\n\n### API\nNo properties.\n\n## _99.WorkOpts\nNo description.\n\n### Description\n| Name | Type | Default Value |\n| --- | --- | --- |\n| `description` | `string \\| nil` | - |\n\n### API\n\n#### description\nNo description.\n\n## _99.Completion\nNo description.\n\n### Description\n| Name | Type | Default Value |\n| --- | --- | --- |\n| `source` | `\"cmp\" \\| \"blink\" \\| nil` | - |\n| `custom_rules` | `string[]` | - |\n| `files` | `_99.Files.Config?` | - |\n\n### API\n\n#### source\nNo description.\n\n#### custom_rules\nNo description.\n\n#### files\nNo description.\n\n## _99.InFlight.Opts\nthis is pure a class for testing.   helps controls timings\n\n### Description\n| Name | Type | Default Value |\n| --- | --- | --- |\n| `throbber_opts` | `_99.Throbber.Opts \\| nil` | - |\n| `in_flight_interval` | `number \\| nil` | - |\n| `enable` | `boolean \\| nil` | - |\n\n### API\n\n#### throbber_opts\noptions for the throbber in the top left\n\n#### in_flight_interval\nfrequency in which the in-flight interval checks to see if it should be\ndisplayed \u002F removed\n\n#### enable\ndefaults to true\n\n## _99.Logger.Options\nNo description.\n\n### Description\n| Name | Type | Default Value |\n| --- | --- | --- |\n| `level` | `number?` | - |\n| `type` | `\"print\" \\| \"void\" \\| \"file\" \\| nil` | - |\n| `path` | `string?` | - |\n| `print_on_error` | `boolean \\| nil` | - |\n| `max_requests_cached` | `number \\| nil` | - |\n\n### API\n\n#### level\nNo description.\n\n#### type\nNo description.\n\n#### path\nNo description.\n\n#### print_on_error\nNo description.\n\n#### max_requests_cached\nNo description.\n\n## _99.Agents.Rule\nNo description.\n\n### Description\n| Name | Type | Default Value |\n| --- | --- | --- |\n| `name` | `string` | - |\n| `path` | `string` | - |\n| `absolute_path` | `string?` | - |\n\n### API\n\n#### name\nNo description.\n\n#### path\nNo description.\n\n#### absolute_path\nNo description.\n\n## Completions\n\nWhen prompting, you can reference rules and files to add context to your request.\n\n- `#` references rules — type `#` in the prompt to autocomplete rule files from your configured rule directories\n- `@` references files — type `@` to fuzzy-search project files. This will exclude files that are in .gitignore.\n\nReferenced content is automatically resolved and injected into the AI context. Native completions work by default. For nvim-cmp or blink.cmp, set `source = \"cmp\"` or `source = \"blink\"`.\n\n## Providers\n99 supports multiple AI CLI backends. Set `provider` in your setup to switch. If you don't set `model`, the provider's default is used.\n\n| Provider | CLI tool | Default model |\n|---|---|---|\n| `OpenCodeProvider` (default) | `opencode` | `opencode\u002Fclaude-sonnet-4-5` |\n| `ClaudeCodeProvider` | `claude` | `claude-sonnet-4-5` |\n| `CursorAgentProvider` | `cursor-agent` | `sonnet-4.5` |\n| `GeminiCLIProvider` | `gemini` | `auto` |\n\n```lua\n_99.setup({\n    provider = _99.Providers.ClaudeCodeProvider,\n    -- model is optional, overrides the provider's default\n    model = \"claude-sonnet-4-5\",\n})\n```\n\n## Extensions\n\n### Telescope Model Selector\n\nIf you have [telescope.nvim](https:\u002F\u002Fgithub.com\u002Fnvim-telescope\u002Ftelescope.nvim) installed, you can switch models on the fly via the Telescope picker:\n\n```lua\nvim.keymap.set(\"n\", \"\u003Cleader>9m\", function()\n  require(\"99.extensions.telescope\").select_model()\nend)\n```\n\nThe selected model is used for all subsequent requests in the current session.\n\n### Telescope Provider Selector\n\nSwitch between providers (OpenCode, Claude, Cursor, Kiro) without restarting Neovim. Switching provider also resets the model to that provider's default.\n\n```lua\nvim.keymap.set(\"n\", \"\u003Cleader>9p\", function()\n  require(\"99.extensions.telescope\").select_provider()\nend)\n```\n\n### fzf-lua\n\nIf you use [fzf-lua](https:\u002F\u002Fgithub.com\u002Fibhagwan\u002Ffzf-lua) instead of telescope, the same pickers are available:\n\n```lua\nvim.keymap.set(\"n\", \"\u003Cleader>9m\", function()\n  require(\"99.extensions.fzf_lua\").select_model()\nend)\n\nvim.keymap.set(\"n\", \"\u003Cleader>9p\", function()\n  require(\"99.extensions.fzf_lua\").select_provider()\nend)\n```\n\n## Reporting a bug\n\nTo report a bug, please provide the full running debug logs. This may require\na bit of back and forth.\n\nPlease do not request features. We will hold a public discussion on Twitch about\nfeatures, which will be a much better jumping point then a bunch of requests that i have to close down. If you do make a feature request ill just shut it down instantly.\n\n### The logs\nTo get the _last_ run's logs execute `:lua require(\"99\").view_logs()`.\n\n### Dont forget\nIf there are secrets or other information in the logs you want to be removed make\nsure that you delete the `query` printing. This will likely contain information you may not want to share.\n\n","99 是一个专为 Neovim 设计的 AI 代理工具，旨在通过结合程序员的能力与大型语言模型的强大功能来增强编程体验。该项目使用 Lua 语言开发，提供了一种智能的工作流程，能够辅助代码搜索和工作处理，而不是完全替代手动编码。它支持自定义日志记录路径、临时目录配置以及技能文件夹列表等高级设置选项，使得用户可以根据自身需求灵活调整。99 特别适合那些希望在保持传统编程习惯的同时，利用人工智能技术提高工作效率的开发者。请注意，当前项目处于测试阶段，API 可能会发生变化。",2,"2026-06-11 03:45:17","high_star"]