\"","```","","**Unified Diff example**","","```diff","*** before/lua/opencode/ui/output_window.lua","@@","- vim.api.nvim_set_option_value('winhighlight', config.ui.window_highlight, { win = windows.output_win })","+ vim.api.nvim_set_option_value('winhighlight', config.ui.window_highlight or '', { win = windows.output_win })","```","","**Python snippet**","","```python","# small helper to format lines","def format_lines(lines):"," return [line.rstrip() for line in lines if line is not None]","```","","**SQL example**","","```sql","-- List recent sessions","SELECT id, created_at, user_id","FROM sessions","WHERE created_at > now() - interval '7 days'","ORDER BY created_at DESC","LIMIT 10;","```","","**HTML fragment**","","```html","",""," Render Test"," "," -- sample Lua inside HTML
"," ","","```","","**Indented (classic) code block**",""," This is an indented code block."," It should render as preformatted text without language highlighting.","","**Shell snippet with inline env vars**","","```bash","export OPENCODE_ENV=development","nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = ' ./tests/minimal/init.lua'})\"","```","","**Mixed inline code examples**","- Use backticks for commands: `./run_tests.sh`","- File path with start line: `lua/opencode/ui/output_window.lua:1`","- API call: `vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)`","","**Small checklist**","- [x] Lua file included ( `lua/opencode/ui/output_window.lua:1`)","- [x] Multiple fenced code blocks","- [x] Several languages: Lua, Bash, JSON, YAML, Python, SQL, HTML, Diff","","If you want more variations (many short blocks, nested lists, tables, or extremely long blocks), tell me which formats or languages to expand and I’ll produce them.","",""],"timestamp":1769091196}
+{
+ "actions": [],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-24 19:32:00)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a17b4dc4c001x19oFZANB8CsEB]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 2,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 3,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 4,
+ 4,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 5,
+ 5,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 6,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-5-mini",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-24 19:32:01)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a17b4e166001vCnLczdZXvqLL6]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "I just want to test the markdown rendering, please write as long session with codeblocksto",
+ "",
+ "[`lua/opencode/ui/output_window.lua`](lua/opencode/ui/output_window.lua)",
+ "",
+ "----",
+ "",
+ "",
+ "Here's a long markdown-rich session with many fenced code blocks to help test rendering. I include the file you provided plus a variety of smaller snippets in different languages and formats.",
+ "",
+ "**File Contents**",
+ "- `lua/opencode/ui/output_window.lua:1`",
+ "",
+ "```lua",
+ "-- lua/opencode/ui/output_window.lua",
+ "local state = require('opencode.state')",
+ "local config = require('opencode.config')",
+ "",
+ "local M = {}",
+ "M.namespace = vim.api.nvim_create_namespace('opencode_output')",
+ "",
+ "function M.create_buf()",
+ " local output_buf = vim.api.nvim_create_buf(false, true)",
+ " vim.api.nvim_set_option_value('filetype', 'opencode_output', { buf = output_buf })",
+ " return output_buf",
+ "end",
+ "",
+ "function M._build_output_win_config()",
+ " return {",
+ " relative = 'editor',",
+ " width = config.ui.window_width or 80,",
+ " row = 2,",
+ " col = 2,",
+ " style = 'minimal',",
+ " border = 'rounded',",
+ " zindex = 40,",
+ " }",
+ "end",
+ "",
+ "function M.mounted(windows)",
+ " windows = windows or state.windows",
+ " if",
+ " not state.windows",
+ " or not state.windows.output_buf",
+ " or not state.windows.output_win",
+ " or not vim.api.nvim_win_is_valid(windows.output_win)",
+ " then",
+ " return false",
+ " end",
+ "",
+ " return true",
+ "end",
+ "",
+ "function M.setup(windows)",
+ " vim.api.nvim_set_option_value('winhighlight', config.ui.window_highlight, { win = windows.output_win })",
+ " vim.api.nvim_set_option_value('wrap', true, { win = windows.output_win })",
+ " vim.api.nvim_set_option_value('number', false, { win = windows.output_win })",
+ " vim.api.nvim_set_option_value('relativenumber', false, { win = windows.output_win })",
+ " vim.api.nvim_set_option_value('modifiable', false, { buf = windows.output_buf })",
+ " vim.api.nvim_set_option_value('buftype', 'nofile', { buf = windows.output_buf })",
+ " vim.api.nvim_set_option_value('swapfile', false, { buf = windows.output_buf })",
+ " vim.api.nvim_set_option_value('winfixbuf', true, { win = windows.output_win })",
+ " vim.api.nvim_set_option_value('winfixheight', true, { win = windows.output_win })",
+ " vim.api.nvim_set_option_value('winfixwidth', true, { win = windows.output_win })",
+ " vim.api.nvim_set_option_value('signcolumn', 'yes', { scope = 'local', win = windows.output_win })",
+ " vim.api.nvim_set_option_value('list', false, { scope = 'local', win = windows.output_win })",
+ "",
+ " M.update_dimensions(windows)",
+ " M.setup_keymaps(windows)",
+ "end",
+ "",
+ "function M.update_dimensions(windows)",
+ " local total_width = vim.api.nvim_get_option_value('columns', {})",
+ " local width = math.floor(total_width * config.ui.window_width)",
+ "",
+ " vim.api.nvim_win_set_config(windows.output_win, { width = width })",
+ "end",
+ "",
+ "function M.get_buf_line_count()",
+ " if not M.mounted() then",
+ " return 0",
+ " end",
+ "",
+ " return vim.api.nvim_buf_line_count(state.windows.output_buf)",
+ "end",
+ "",
+ "---Set the output buffer contents",
+ "---@param lines string[] The lines to set",
+ "---@param start_line? integer The starting line to set, defaults to 0",
+ "---@param end_line? integer The last line to set, defaults to -1",
+ "function M.set_lines(lines, start_line, end_line)",
+ " if not M.mounted() then",
+ " return",
+ " end",
+ "",
+ " start_line = start_line or 0",
+ " end_line = end_line or -1",
+ "",
+ " local windows = state.windows",
+ " if not windows or not windows.output_buf then",
+ " return",
+ " end",
+ "",
+ " vim.api.nvim_set_option_value('modifiable', true, { buf = windows.output_buf })",
+ " vim.api.nvim_buf_set_lines(windows.output_buf, start_line, end_line, false, lines)",
+ " vim.api.nvim_set_option_value('modifiable', false, { buf = windows.output_buf })",
+ "end",
+ "",
+ "---Clear output buf extmarks",
+ "---@param start_line? integer Line to start clearing, defaults 0",
+ "---@param end_line? integer Line to to clear until, defaults to -1",
+ "function M.clear_extmarks(start_line, end_line)",
+ " if not M.mounted() or not state.windows.output_buf then",
+ " return",
+ " end",
+ "",
+ " start_line = start_line or 0",
+ " end_line = end_line or -1",
+ "",
+ " vim.api.nvim_buf_clear_namespace(state.windows.output_buf, M.namespace, start_line, end_line)",
+ "end",
+ "",
+ "---Apply extmarks to the output buffer",
+ "---@param extmarks table Extmarks indexed by line",
+ "---@param line_offset? integer Line offset to apply to extmarks, defaults to 0",
+ "function M.set_extmarks(extmarks, line_offset)",
+ " if not M.mounted() or not extmarks or type(extmarks) ~= 'table' then",
+ " return",
+ " end",
+ "",
+ " line_offset = line_offset or 0",
+ "",
+ " local output_buf = state.windows.output_buf",
+ "",
+ " for line_idx, marks in pairs(extmarks) do",
+ " for _, mark in ipairs(marks) do",
+ " local actual_mark = type(mark) == 'function' and mark() or mark",
+ " local target_line = line_offset + line_idx",
+ " if actual_mark.end_row then",
+ " actual_mark.end_row = actual_mark.end_row + line_offset",
+ " end",
+ " local start_col = actual_mark.start_col",
+ " if actual_mark.start_col then",
+ " actual_mark.start_col = nil",
+ " end",
+ " pcall(vim.api.nvim_buf_set_extmark, output_buf, M.namespace, target_line, start_col or 0, actual_mark)",
+ " end",
+ " end",
+ "end",
+ "",
+ "function M.focus_output(should_stop_insert)",
+ " if should_stop_insert then",
+ " vim.cmd('stopinsert')",
+ " end",
+ " vim.api.nvim_set_current_win(state.windows.output_win)",
+ "end",
+ "",
+ "function M.close()",
+ " if M.mounted() then",
+ " return",
+ " end",
+ " pcall(vim.api.nvim_win_close, state.windows.output_win, true)",
+ " pcall(vim.api.nvim_buf_delete, state.windows.output_buf, { force = true })",
+ "end",
+ "",
+ "function M.setup_keymaps(windows)",
+ " local keymap = require('opencode.keymap')",
+ " keymap.setup_window_keymaps(config.keymap.output_window, windows.output_buf)",
+ "end",
+ "",
+ "function M.setup_autocmds(windows, group)",
+ " vim.api.nvim_create_autocmd('WinEnter', {",
+ " group = group,",
+ " buffer = windows.output_buf,",
+ " callback = function()",
+ " vim.cmd('stopinsert')",
+ " state.last_focused_opencode_window = 'output'",
+ " require('opencode.ui.input_window').refresh_placeholder(state.windows)",
+ " end,",
+ " })",
+ "",
+ " vim.api.nvim_create_autocmd('BufEnter', {",
+ " group = group,",
+ " buffer = windows.output_buf,",
+ " callback = function()",
+ " vim.cmd('stopinsert')",
+ " state.last_focused_opencode_window = 'output'",
+ " require('opencode.ui.input_window').refresh_placeholder(state.windows)",
+ " end,",
+ " })",
+ "",
+ " state.subscribe('current_permission', function()",
+ " require('opencode.keymap').toggle_permission_keymap(windows.output_buf)",
+ " end)",
+ "end",
+ "",
+ "function M.clear()",
+ " M.set_lines({})",
+ " M.clear_extmarks()",
+ "end",
+ "",
+ "return M",
+ "```",
+ "",
+ "**Shell / Commands**",
+ "",
+ "```bash",
+ "# show project root and run tests",
+ "pwd",
+ "ls -la",
+ " ./run_tests.sh",
+ "```",
+ "",
+ "**Short Lua examples**",
+ "",
+ "```lua",
+ "-- Print buffer line count if mounted",
+ "local out = require('opencode.ui.output_window')",
+ "if out.mounted() then",
+ " print('Lines:', out.get_buf_line_count())",
+ "else",
+ " print('Output window not mounted.')",
+ "end",
+ "```",
+ "",
+ "**JSON sample**",
+ "",
+ "```json",
+ "{",
+ " \"name\": \"opencode.nvim\",",
+ " \"version\": \"0.0.0\",",
+ " \"tests\": {",
+ " \"unit\": 128,",
+ " \"manual\": 12",
+ " }",
+ "}",
+ "```",
+ "",
+ "**YAML sample**",
+ "",
+ "```yaml",
+ "ui:",
+ " window_width: 0.5",
+ " window_highlight: \"Normal:NormalFloat\"",
+ "keymap:",
+ " output_window:",
+ " close: \"\"",
+ " focus: \"\"",
+ "```",
+ "",
+ "**Unified Diff example**",
+ "",
+ "```diff",
+ "*** before/lua/opencode/ui/output_window.lua",
+ "@@",
+ "- vim.api.nvim_set_option_value('winhighlight', config.ui.window_highlight, { win = windows.output_win })",
+ "+ vim.api.nvim_set_option_value('winhighlight', config.ui.window_highlight or '', { win = windows.output_win })",
+ "```",
+ "",
+ "**Python snippet**",
+ "",
+ "```python",
+ "# small helper to format lines",
+ "def format_lines(lines):",
+ " return [line.rstrip() for line in lines if line is not None]",
+ "```",
+ "",
+ "**SQL example**",
+ "",
+ "```sql",
+ "-- List recent sessions",
+ "SELECT id, created_at, user_id",
+ "FROM sessions",
+ "WHERE created_at > now() - interval '7 days'",
+ "ORDER BY created_at DESC",
+ "LIMIT 10;",
+ "```",
+ "",
+ "**HTML fragment**",
+ "",
+ "```html",
+ "",
+ "",
+ " Render Test",
+ " ",
+ " -- sample Lua inside HTML
",
+ " ",
+ "",
+ "```",
+ "",
+ "**Indented (classic) code block**",
+ "",
+ " This is an indented code block.",
+ " It should render as preformatted text without language highlighting.",
+ "",
+ "**Shell snippet with inline env vars**",
+ "",
+ "```bash",
+ "export OPENCODE_ENV=development",
+ "nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = ' ./tests/minimal/init.lua'})\"",
+ "```",
+ "",
+ "**Mixed inline code examples**",
+ "- Use backticks for commands: `./run_tests.sh`",
+ "- File path with start line: `lua/opencode/ui/output_window.lua:1`",
+ "- API call: `vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)`",
+ "",
+ "**Small checklist**",
+ "- [x] Lua file included ( `lua/opencode/ui/output_window.lua:1`)",
+ "- [x] Multiple fenced code blocks",
+ "- [x] Several languages: Lua, Bash, JSON, YAML, Python, SQL, HTML, Diff",
+ "",
+ "If you want more variations (many short blocks, nested lists, tables, or extremely long blocks), tell me which formats or languages to expand and I’ll produce them.",
+ "",
+ ""
+ ],
+ "timestamp": 1770748576
+}
\ No newline at end of file
diff --git a/tests/data/permission-ask-new-approve.expected.json b/tests/data/permission-ask-new-approve.expected.json
index 4340e8d2..d7394599 100644
--- a/tests/data/permission-ask-new-approve.expected.json
+++ b/tests/data/permission-ask-new-approve.expected.json
@@ -1 +1,820 @@
-{"actions":[{"args":["5ba6e95774829e7f501299039b72b72dc32c6620"],"type":"diff_revert_selected_file","display_line":36,"text":"[R]evert file","key":"R","range":{"from":36,"to":36}},{"args":["5ba6e95774829e7f501299039b72b72dc32c6620"],"type":"diff_revert_all","display_line":36,"text":"Revert [A]ll","key":"A","range":{"from":36,"to":36}},{"args":["5ba6e95774829e7f501299039b72b72dc32c6620"],"type":"diff_open","display_line":36,"text":"[D]iff","key":"D","range":{"from":36,"to":36}}],"extmarks":[[1,1,0,{"right_gravity":true,"ns_id":3,"priority":10,"virt_text_hide":false,"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2026-01-05 14:07:54)","OpencodeHint"],[" [msg_b8e7c60a2001Kisjwk2mVB4dye]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"virt_text_repeat_linebreak":false}],[2,2,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"virt_text_repeat_linebreak":true}],[3,3,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"virt_text_repeat_linebreak":true}],[4,4,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"virt_text_repeat_linebreak":true}],[5,5,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"virt_text_repeat_linebreak":true}],[6,6,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"virt_text_repeat_linebreak":true}],[7,7,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"virt_text_repeat_linebreak":true}],[8,8,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"virt_text_repeat_linebreak":true}],[9,10,0,{"right_gravity":true,"ns_id":3,"priority":10,"virt_text_hide":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2026-01-05 14:07:54)","OpencodeHint"],[" [msg_b8e7c60f1001aEWYlAaDRXQ4aJ]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"virt_text_repeat_linebreak":false}],[10,12,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[11,13,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[12,14,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[13,15,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[14,16,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[15,17,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[16,18,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[17,19,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[18,20,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[19,21,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[20,22,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[21,23,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[22,24,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[23,25,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[24,26,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[25,27,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[26,28,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[27,29,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[28,30,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[29,31,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[30,32,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[31,33,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[32,34,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[33,39,0,{"right_gravity":true,"ns_id":3,"priority":10,"virt_text_hide":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2026-01-05 14:08:26)","OpencodeHint"],[" [msg_b8e7cde9e0013hRkUyt0X2yMil]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"virt_text_repeat_linebreak":false}]],"timestamp":1769091210,"lines":["----","","","@no-trust run a git status and tell me what files are changed","","[`lua/opencode/ui/formatter.lua`](lua/opencode/ui/formatter.lua)","","**Diagnostics:** (11)","","----","","","** run** `Shows working tree status`","","`````bash","> git status","","On branch main","Your branch is up to date with 'origin/main'.","","Changes not staged for commit:"," (use \"git add ...\" to update what will be committed)"," (use \"git restore ...\" to discard changes in working directory)","\tmodified: lua/opencode/event_manager.lua","\tmodified: lua/opencode/ui/formatter.lua","\tmodified: lua/opencode/ui/renderer.lua","","Untracked files:"," (use \"git add ...\" to include in what will be committed)","\ttest.lua","\ttests/data/permission_ask_new.json","","no changes added to commit (use \"git add\" and/or \"git commit -a\")","","`````","","** Created Snapshot** `5ba6e957`","","----","","","Here are the files that have been changed according to git status:","","- Modified (but not staged):"," - `lua/opencode/event_manager.lua`"," - `lua/opencode/ui/formatter.lua`"," - `lua/opencode/ui/renderer.lua`","","- Untracked files:"," - `test.lua`"," - `tests/data/permission_ask_new.json`","","No files are currently staged for commit. Let me know if you want more details (like the diff), want to stage/commit, or need help with anything else!","",""]}
+{
+ "actions": [
+ {
+ "args": [
+ "5ba6e95774829e7f501299039b72b72dc32c6620"
+ ],
+ "display_line": 36,
+ "key": "R",
+ "range": {
+ "from": 36,
+ "to": 36
+ },
+ "text": "[R]evert file",
+ "type": "diff_revert_selected_file"
+ },
+ {
+ "args": [
+ "5ba6e95774829e7f501299039b72b72dc32c6620"
+ ],
+ "display_line": 36,
+ "key": "A",
+ "range": {
+ "from": 36,
+ "to": 36
+ },
+ "text": "Revert [A]ll",
+ "type": "diff_revert_all"
+ },
+ {
+ "args": [
+ "5ba6e95774829e7f501299039b72b72dc32c6620"
+ ],
+ "display_line": 36,
+ "key": "D",
+ "range": {
+ "from": 36,
+ "to": 36
+ },
+ "text": "[D]iff",
+ "type": "diff_open"
+ }
+ ],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2026-01-05 14:07:54)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_b8e7c60a2001Kisjwk2mVB4dye]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 2,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 3,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 4,
+ 4,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 5,
+ 5,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 6,
+ 6,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 7,
+ 7,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 8,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 9,
+ 10,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-4.1",
+ "OpencodeHint"
+ ],
+ [
+ " (2026-01-05 14:07:54)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_b8e7c60f1001aEWYlAaDRXQ4aJ]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 10,
+ 12,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 11,
+ 13,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 12,
+ 14,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 13,
+ 15,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 14,
+ 16,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 15,
+ 17,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 16,
+ 18,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 17,
+ 19,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 18,
+ 20,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 19,
+ 21,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 20,
+ 22,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 21,
+ 23,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 22,
+ 24,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 23,
+ 25,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 24,
+ 26,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 25,
+ 27,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 26,
+ 28,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 27,
+ 29,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 28,
+ 30,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 29,
+ 31,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 30,
+ 32,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 31,
+ 33,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 32,
+ 34,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 33,
+ 39,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-4.1",
+ "OpencodeHint"
+ ],
+ [
+ " (2026-01-05 14:08:26)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_b8e7cde9e0013hRkUyt0X2yMil]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "@no-trust run a git status and tell me what files are changed",
+ "",
+ "[`lua/opencode/ui/formatter.lua`](lua/opencode/ui/formatter.lua)",
+ "",
+ "**Diagnostics:** (11)",
+ "",
+ "----",
+ "",
+ "",
+ "** run** `Shows working tree status`",
+ "",
+ "`````bash",
+ "> git status",
+ "",
+ "On branch main",
+ "Your branch is up to date with 'origin/main'.",
+ "",
+ "Changes not staged for commit:",
+ " (use \"git add ...\" to update what will be committed)",
+ " (use \"git restore ...\" to discard changes in working directory)",
+ "\tmodified: lua/opencode/event_manager.lua",
+ "\tmodified: lua/opencode/ui/formatter.lua",
+ "\tmodified: lua/opencode/ui/renderer.lua",
+ "",
+ "Untracked files:",
+ " (use \"git add ...\" to include in what will be committed)",
+ "\ttest.lua",
+ "\ttests/data/permission_ask_new.json",
+ "",
+ "no changes added to commit (use \"git add\" and/or \"git commit -a\")",
+ "",
+ "`````",
+ "",
+ "** Created Snapshot** `5ba6e957`",
+ "",
+ "----",
+ "",
+ "",
+ "Here are the files that have been changed according to git status:",
+ "",
+ "- Modified (but not staged):",
+ " - `lua/opencode/event_manager.lua`",
+ " - `lua/opencode/ui/formatter.lua`",
+ " - `lua/opencode/ui/renderer.lua`",
+ "",
+ "- Untracked files:",
+ " - `test.lua`",
+ " - `tests/data/permission_ask_new.json`",
+ "",
+ "No files are currently staged for commit. Let me know if you want more details (like the diff), want to stage/commit, or need help with anything else!",
+ "",
+ ""
+ ],
+ "timestamp": 1770748577
+}
\ No newline at end of file
diff --git a/tests/data/permission-ask-new-approve.json b/tests/data/permission-ask-new-approve.json
index d6849d60..c05dcfba 100644
--- a/tests/data/permission-ask-new-approve.json
+++ b/tests/data/permission-ask-new-approve.json
@@ -1 +1,793 @@
-[{"properties":{"info":{"title":"New session - 2026-01-05T14:07:52.149Z","version":"1.1.2","directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_47183a8abffeZzOLeJ3j2KV8f8","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","time":{"updated":1767622072149,"created":1767622072149}}},"type":"session.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"info":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"role":"user","id":"msg_b8e7c60a2001Kisjwk2mVB4dye","agent":"build","system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","time":{"created":1767622074530}}},"type":"message.updated"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","id":"prt_b8e7c60a3001M2zsH9REfPdlQt","text":"@no-trust run a git status and tell me what files are changed","messageID":"msg_b8e7c60a2001Kisjwk2mVB4dye"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","id":"prt_b8e7c60a3003Ta9NcXkN0lb0lF","messageID":"msg_b8e7c60a2001Kisjwk2mVB4dye","text":"Called the Read tool with the following input: {\"filePath\":\"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\"}","synthetic":true}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","id":"prt_b8e7c60a7001d3WhKOu2vCR4Cf","messageID":"msg_b8e7c60a2001Kisjwk2mVB4dye","text":"\n00001| local context_module = require('opencode.context')\n00002| local icons = require('opencode.ui.icons')\n00003| local util = require('opencode.util')\n00004| local Output = require('opencode.ui.output')\n00005| local state = require('opencode.state')\n00006| local config = require('opencode.config')\n00007| local snapshot = require('opencode.snapshot')\n00008| local mention = require('opencode.ui.mention')\n00009| \n00010| local M = {}\n00011| \n00012| M.separator = {\n00013| '----',\n00014| '',\n00015| }\n00016| \n00017| ---@param output Output\n00018| ---@param part OpencodeMessagePart\n00019| function M._format_reasoning(output, part)\n00020| local text = vim.trim(part.text or '')\n00021| if text == '' then\n00022| return\n00023| end\n00024| \n00025| local start_line = output:get_line_count() + 1\n00026| \n00027| local title = 'Reasoning'\n00028| local time = part.time\n00029| if time and type(time) == 'table' and time.start then\n00030| local start_text = util.format_time(time.start) or ''\n00031| local end_text = (time['end'] and util.format_time(time['end'])) or nil\n00032| if end_text and end_text ~= '' then\n00033| title = string.format('%s (%s - %s)', title, start_text, end_text)\n00034| elseif start_text ~= '' then\n00035| title = string.format('%s (%s)', title, start_text)\n00036| end\n00037| end\n00038| \n00039| M._format_action(output, icons.get('reasoning') .. ' ' .. title, '')\n00040| \n00041| if config.ui.output.tools.show_reasoning_output then\n00042| output:add_empty_line()\n00043| output:add_lines(vim.split(text, '\\n'))\n00044| output:add_empty_line()\n00045| end\n00046| \n00047| local end_line = output:get_line_count()\n00048| if end_line - start_line > 1 then\n00049| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1, 'OpencodeReasoningText')\n00050| else\n00051| output:add_extmark(start_line - 1, {\n00052| line_hl_group = 'OpencodeReasoningText',\n00053| } --[[@as OutputExtmark]])\n00054| end\n00055| end\n00056| \n00057| function M._handle_permission_request(output, part)\n00058| if part.state and part.state.status == 'error' and part.state.error then\n00059| if part.state.error:match('rejected permission') then\n00060| state.current_permission = nil\n00061| else\n00062| vim.notify('Unknown part state error: ' .. part.state.error)\n00063| end\n00064| return\n00065| end\n00066| \n00067| M._format_permission_request(output)\n00068| end\n00069| \n00070| function M._format_permission_request(output)\n00071| local keys\n00072| \n00073| if require('opencode.ui.ui').is_opencode_focused() then\n00074| keys = {\n00075| config.keymap.permission.accept,\n00076| config.keymap.permission.accept_all,\n00077| config.keymap.permission.deny,\n00078| }\n00079| else\n00080| keys = {\n00081| config.get_key_for_function('editor', 'permission_accept'),\n00082| config.get_key_for_function('editor', 'permission_accept_all'),\n00083| config.get_key_for_function('editor', 'permission_deny'),\n00084| }\n00085| end\n00086| \n00087| output:add_empty_line()\n00088| output:add_line('> [!WARNING] Permission required to run this tool.')\n00089| output:add_line('>')\n00090| output:add_line(('> Accept `%s` Always `%s` Deny `%s`'):format(unpack(keys)))\n00091| output:add_empty_line()\n00092| end\n00093| \n00094| ---Calculate statistics for reverted messages and tool calls\n00095| ---@param messages {info: MessageInfo, parts: OpencodeMessagePart[]}[] All messages in the session\n00096| ---@param revert_index number Index of the message where revert occurred\n00097| ---@param revert_info SessionRevertInfo Revert information\n00098| ---@return {messages: number, tool_calls: number, files: table}\n00099| function M._calculate_revert_stats(messages, revert_index, revert_info)\n00100| local stats = {\n00101| messages = 0,\n00102| tool_calls = 0,\n00103| files = {}, -- { [filename] = { additions = n, deletions = m } }\n00104| }\n00105| \n00106| for i = revert_index, #messages do\n00107| local msg = messages[i]\n00108| if msg.info.role == 'user' then\n00109| stats.messages = stats.messages + 1\n00110| end\n00111| if msg.parts then\n00112| for _, part in ipairs(msg.parts) do\n00113| if part.type == 'tool' then\n00114| stats.tool_calls = stats.tool_calls + 1\n00115| end\n00116| end\n00117| end\n00118| end\n00119| \n00120| if revert_info.diff then\n00121| local current_file = nil\n00122| for line in revert_info.diff:gmatch('[^\\r\\n]+') do\n00123| local file_a = line:match('^%-%-%- ([ab]/.+)')\n00124| local file_b = line:match('^%+%+%+ ([ab]/.+)')\n00125| if file_b then\n00126| current_file = file_b:gsub('^[ab]/', '')\n00127| if not stats.files[current_file] then\n00128| stats.files[current_file] = { additions = 0, deletions = 0 }\n00129| end\n00130| elseif file_a then\n00131| current_file = file_a:gsub('^[ab]/', '')\n00132| if not stats.files[current_file] then\n00133| stats.files[current_file] = { additions = 0, deletions = 0 }\n00134| end\n00135| elseif line:sub(1, 1) == '+' and not line:match('^%+%+%+') then\n00136| if current_file then\n00137| stats.files[current_file].additions = stats.files[current_file].additions + 1\n00138| end\n00139| elseif line:sub(1, 1) == '-' and not line:match('^%-%-%-') then\n00140| if current_file then\n00141| stats.files[current_file].deletions = stats.files[current_file].deletions + 1\n00142| end\n00143| end\n00144| end\n00145| end\n00146| \n00147| return stats\n00148| end\n00149| \n00150| ---Format the revert callout with statistics\n00151| ---@param session_data OpencodeMessage[] All messages in the session\n00152| ---@param start_idx number Index of the message where revert occurred\n00153| ---@return Output output object representing the lines, extmarks, and actions\n00154| function M._format_revert_message(session_data, start_idx)\n00155| local output = Output.new()\n00156| local stats = M._calculate_revert_stats(session_data, start_idx, state.active_session.revert)\n00157| local message_text = stats.messages == 1 and 'message' or 'messages'\n00158| local tool_text = stats.tool_calls == 1 and 'tool call' or 'tool calls'\n00159| \n00160| output:add_lines(M.separator)\n00161| output:add_line(\n00162| string.format('> %d %s reverted, %d %s reverted', stats.messages, message_text, stats.tool_calls, tool_text)\n00163| )\n00164| output:add_line('>')\n00165| output:add_line('> type `/redo` to restore.')\n00166| output:add_empty_line()\n00167| \n00168| if stats.files and next(stats.files) then\n00169| for file, fstats in pairs(stats.files) do\n00170| local file_diff = {}\n00171| if fstats.additions > 0 then\n00172| table.insert(file_diff, '+' .. fstats.additions)\n00173| end\n00174| if fstats.deletions > 0 then\n00175| table.insert(file_diff, '-' .. fstats.deletions)\n00176| end\n00177| if #file_diff > 0 then\n00178| local line_str = string.format(icons.get('file') .. '%s: %s', file, table.concat(file_diff, ' '))\n00179| local line_idx = output:add_line(line_str)\n00180| local col = #(' ' .. file .. ': ')\n00181| for _, diff in ipairs(file_diff) do\n00182| local hl_group = diff:sub(1, 1) == '+' and 'OpencodeDiffAddText' or 'OpencodeDiffDeleteText'\n00183| output:add_extmark(line_idx - 1, {\n00184| virt_text = { { diff, hl_group } },\n00185| virt_text_pos = 'inline',\n00186| virt_text_win_col = col,\n00187| priority = 1000,\n00188| } --[[@as OutputExtmark]])\n00189| col = col + #diff + 1\n00190| end\n00191| end\n00192| end\n00193| end\n00194| return output\n00195| end\n00196| \n00197| local function add_action(output, text, action_type, args, key, line)\n00198| -- actions use api-indexing (e.g. 0 indexed)\n00199| line = (line or output:get_line_count()) - 1\n00200| output:add_action({\n00201| text = text,\n00202| type = action_type,\n00203| args = args,\n00204| key = key,\n00205| display_line = line,\n00206| range = { from = line, to = line },\n00207| })\n00208| end\n00209| \n00210| ---@param output Output Output object to write to\n00211| ---@param part OpencodeMessagePart\n00212| function M._format_patch(output, part)\n00213| if not part.hash then\n00214| return\n00215| end\n00216| \n00217| local restore_points = snapshot.get_restore_points_by_parent(part.hash) or {}\n00218| M._format_action(output, icons.get('snapshot') .. ' Created Snapshot', vim.trim(part.hash:sub(1, 8)))\n00219| \n00220| -- Anchor all snapshot-level actions to the snapshot header line\n00221| add_action(output, '[R]evert file', 'diff_revert_selected_file', { part.hash }, 'R')\n00222| add_action(output, 'Revert [A]ll', 'diff_revert_all', { part.hash }, 'A')\n00223| add_action(output, '[D]iff', 'diff_open', { part.hash }, 'D')\n00224| \n00225| if #restore_points > 0 then\n00226| for _, restore_point in ipairs(restore_points) do\n00227| output:add_line(\n00228| string.format(\n00229| ' %s Restore point `%s` - %s ',\n00230| icons.get('restore_point'),\n00231| vim.trim(restore_point.id:sub(1, 8)),\n00232| util.format_time(restore_point.created_at)\n00233| )\n00234| )\n00235| add_action(output, 'Restore [A]ll', 'diff_restore_snapshot_all', { restore_point.id }, 'A')\n00236| add_action(output, '[R]estore file', 'diff_restore_snapshot_file', { restore_point.id }, 'R')\n00237| end\n00238| end\n00239| end\n00240| \n00241| ---@param output Output Output object to write to\n00242| ---@param message MessageInfo\n00243| function M._format_error(output, message)\n00244| output:add_empty_line()\n00245| M._format_callout(output, 'ERROR', vim.inspect(message.error))\n00246| end\n00247| \n00248| ---@param message OpencodeMessage\n00249| ---@return Output\n00250| function M.format_message_header(message)\n00251| local output = Output.new()\n00252| \n00253| output:add_lines(M.separator)\n00254| local role = message.info.role or 'unknown'\n00255| local icon = message.info.role == 'user' and icons.get('header_user') or icons.get('header_assistant')\n00256| \n00257| local time = message.info.time and message.info.time.created or nil\n00258| local time_text = (time and ' (' .. util.format_time(time) .. ')' or '')\n00259| local role_hl = 'OpencodeMessageRole' .. role:sub(1, 1):upper() .. role:sub(2)\n00260| local model_text = message.info.modelID and ' ' .. message.info.modelID or ''\n00261| \n00262| local debug_text = config.debug.show_ids and ' [' .. message.info.id .. ']' or ''\n00263| \n00264| local display_name\n00265| if role == 'assistant' then\n00266| local mode = message.info.mode\n00267| if mode and mode ~= '' then\n00268| display_name = mode:upper()\n00269| else\n00270| -- For the most recent assistant message, show current_mode if mode is missing\n00271| -- This handles new messages that haven't been stamped yet\n00272| local is_last_message = #state.messages == 0 or message.info.id == state.messages[#state.messages].info.id\n00273| if is_last_message and state.current_mode and state.current_mode ~= '' then\n00274| display_name = state.current_mode:upper()\n00275| else\n00276| display_name = 'ASSISTANT'\n00277| end\n00278| end\n00279| else\n00280| display_name = role:upper()\n00281| end\n00282| \n00283| output:add_extmark(output:get_line_count() - 1, {\n00284| virt_text = {\n00285| { icon, role_hl },\n00286| { ' ' },\n00287| { display_name, role_hl },\n00288| { model_text, 'OpencodeHint' },\n00289| { time_text, 'OpencodeHint' },\n00290| { debug_text, 'OpencodeHint' },\n00291| },\n00292| virt_text_win_col = -3,\n00293| priority = 10,\n00294| } --[[@as OutputExtmark]])\n00295| \n00296| -- Only want to show the error if we have no parts. If we have parts, they'll\n00297| -- handle rendering the error\n00298| if\n00299| role == 'assistant'\n00300| and message.info.error\n00301| and message.info.error ~= ''\n00302| and (not message.parts or #message.parts == 0)\n00303| then\n00304| local error = message.info.error\n00305| local error_message = error.data and error.data.message or vim.inspect(error)\n00306| \n00307| output:add_line('')\n00308| M._format_callout(output, 'ERROR', error_message)\n00309| end\n00310| \n00311| output:add_line('')\n00312| return output\n00313| end\n00314| \n00315| ---@param output Output Output object to write to\n00316| ---@param callout string Callout type (e.g., 'ERROR', 'TODO')\n00317| ---@param text string Callout text content\n00318| ---@param title? string Optional title for the callout\n00319| function M._format_callout(output, callout, text, title)\n00320| title = title and title .. ' ' or ''\n00321| local win_width = (state.windows and state.windows.output_win and vim.api.nvim_win_is_valid(state.windows.output_win))\n00322| and vim.api.nvim_win_get_width(state.windows.output_win)\n00323| or config.ui.window_width\n00324| or 80\n00325| if #text > win_width - 4 then\n00326| local ok, substituted = pcall(vim.fn.substitute, text, '\\v(.{' .. (win_width - 8) .. '})', '\\1\\n', 'g')\n00327| text = ok and substituted or text\n00328| end\n00329| \n00330| -- Trim off any trailing newlines so there isn't an extra line in the\n00331| -- extmarks section\n00332| local lines = vim.split(text:gsub('\\n$', ''), '\\n')\n00333| if #lines == 1 and title == '' then\n00334| output:add_line('> [!' .. callout .. '] ' .. lines[1])\n00335| else\n00336| output:add_line('> [!' .. callout .. ']' .. title)\n00337| output:add_line('>')\n00338| output:add_lines(lines, '> ')\n00339| end\n00340| end\n00341| \n00342| ---@param output Output Output object to write to\n00343| ---@param text string\n00344| ---@param message? OpencodeMessage Optional message object to extract mentions from\n00345| function M._format_user_prompt(output, text, message)\n00346| local start_line = output:get_line_count()\n00347| \n00348| output:add_lines(vim.split(text, '\\n'))\n00349| \n00350| local end_line = output:get_line_count()\n00351| \n00352| local end_line_extmark_offset = 0\n00353| \n00354| local mentions = {}\n00355| if message and message.parts then\n00356| -- message.parts will only be filled out on a re-render\n00357| -- we need to collect the mentions here\n00358| for _, part in ipairs(message.parts) do\n00359| if part.type == 'file' then\n00360| -- we're rerendering this part and we have files, the space after the user prompt\n00361| -- also needs an extmark\n00362| end_line_extmark_offset = 1\n00363| if part.source and part.source.text then\n00364| table.insert(mentions, part.source.text)\n00365| end\n00366| elseif part.type == 'agent' then\n00367| if part.source then\n00368| table.insert(mentions, part.source)\n00369| end\n00370| end\n00371| end\n00372| end\n00373| \n00374| if #mentions > 0 then\n00375| mention.highlight_mentions_in_output(output, text, mentions, start_line)\n00376| end\n00377| \n00378| M._add_vertical_border(output, start_line, end_line + end_line_extmark_offset, 'OpencodeMessageRoleUser', -3)\n00379| end\n00380| \n00381| ---@param output Output Output object to write to\n00382| ---@param part OpencodeMessagePart\n00383| function M._format_selection_context(output, part)\n00384| local json = context_module.decode_json_context(part.text or '', 'selection')\n00385| if not json then\n00386| return\n00387| end\n00388| local start_line = output:get_line_count()\n00389| output:add_lines(vim.split(json.content or '', '\\n'))\n00390| output:add_empty_line()\n00391| \n00392| local end_line = output:get_line_count()\n00393| \n00394| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00395| end\n00396| \n00397| ---@param output Output Output object to write to\n00398| ---@param part OpencodeMessagePart\n00399| function M._format_cursor_data_context(output, part)\n00400| local json = context_module.decode_json_context(part.text or '', 'cursor-data')\n00401| if not json then\n00402| return\n00403| end\n00404| local start_line = output:get_line_count()\n00405| output:add_line('Line ' .. json.line .. ':')\n00406| output:add_lines(vim.split(json.line_content or '', '\\n'))\n00407| output:add_empty_line()\n00408| \n00409| local end_line = output:get_line_count()\n00410| \n00411| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00412| end\n00413| \n00414| ---@param output Output Output object to write to\n00415| ---@param part OpencodeMessagePart\n00416| function M._format_diagnostics_context(output, part)\n00417| local json = context_module.decode_json_context(part.text or '', 'diagnostics')\n00418| if not json then\n00419| return\n00420| end\n00421| local start_line = output:get_line_count()\n00422| local diagnostics = json.content --[[@as OpencodeDiagnostic[] ]]\n00423| if not diagnostics or type(diagnostics) ~= 'table' or #diagnostics == 0 then\n00424| return\n00425| end\n00426| \n00427| local diagnostics_count = { error = 0, warn = 0, info = 0 }\n00428| local diagnostics_icons = {\n00429| error = icons.get('error'),\n00430| warn = icons.get('warning'),\n00431| info = icons.get('info'),\n00432| }\n00433| \n00434| for _, diag in ipairs(diagnostics) do\n00435| local name = vim.diagnostic.severity[diag.severity]:lower()\n00436| diagnostics_count[name] = diagnostics_count[name] + 1\n00437| end\n00438| \n00439| local diag_line = '**Diagnostics:**'\n00440| for name, count in pairs(diagnostics_count) do\n00441| if count > 0 then\n00442| diag_line = diag_line .. (string.format(' %s(%d)', diagnostics_icons[name], count))\n00443| end\n00444| end\n00445| output:add_line(diag_line)\n00446| output:add_empty_line()\n00447| local end_line = output:get_line_count()\n00448| \n00449| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00450| end\n00451| \n00452| ---Format and display the file path in the context\n00453| ---@param output Output Output object to write to\n00454| ---@param path string|nil File path\n00455| function M._format_context_file(output, path)\n00456| if not path or path == '' then\n00457| return\n00458| end\n00459| local cwd = vim.fn.getcwd()\n00460| if vim.startswith(path, cwd) then\n00461| path = path:sub(#cwd + 2)\n00462| end\n00463| return output:add_line(string.format('[%s](%s)', path, path))\n00464| end\n00465| \n00466| ---@param output Output Output object to write to\n00467| ---@param text string\n00468| function M._format_assistant_message(output, text)\n00469| local reference_picker = require('opencode.ui.reference_picker')\n00470| local references = reference_picker.parse_references(text, '')\n00471| \n00472| -- If no references, just add the text as-is\n00473| if #references == 0 then\n00474| output:add_lines(vim.split(text, '\\n'))\n00475| return\n00476| end\n00477| \n00478| -- Sort references by match_start position (ascending)\n00479| table.sort(references, function(a, b)\n00480| return a.match_start < b.match_start\n00481| end)\n00482| \n00483| -- Build a new text with icons inserted before each reference\n00484| local result = ''\n00485| local last_pos = 1\n00486| local ref_icon = icons.get('reference')\n00487| \n00488| for _, ref in ipairs(references) do\n00489| -- Add text before this reference\n00490| result = result .. text:sub(last_pos, ref.match_start - 1)\n00491| -- Add the icon and the reference\n00492| result = result .. ref_icon .. text:sub(ref.match_start, ref.match_end)\n00493| last_pos = ref.match_end + 1\n00494| end\n00495| \n00496| -- Add any remaining text after the last reference\n00497| if last_pos <= #text then\n00498| result = result .. text:sub(last_pos)\n00499| end\n00500| \n00501| output:add_lines(vim.split(result, '\\n'))\n00502| end\n00503| \n00504| ---@param output Output Output object to write to\n00505| ---@param tool_type string Tool type (e.g., 'run', 'read', 'edit', etc.)\n00506| ---@param value string Value associated with the action (e.g., filename, command)\n00507| function M._format_action(output, tool_type, value)\n00508| if not tool_type or not value then\n00509| return\n00510| end\n00511| local line = string.format('**%s** %s', tool_type, value and #value > 0 and ('`' .. value .. '`') or '')\n00512| \n00513| output:add_line(line)\n00514| end\n00515| \n00516| ---@param output Output Output object to write to\n00517| ---@param input BashToolInput data for the tool\n00518| ---@param metadata BashToolMetadata Metadata for the tool use\n00519| function M._format_bash_tool(output, input, metadata)\n00520| M._format_action(output, icons.get('run') .. ' run', input and input.description)\n00521| \n00522| if not config.ui.output.tools.show_output then\n00523| return\n00524| end\n00525| \n00526| if metadata.output or metadata.command or input.command then\n00527| local command = input.command or metadata.command or ''\n00528| local command_output = metadata.output and metadata.output ~= '' and ('\\n' .. metadata.output) or ''\n00529| M._format_code(output, vim.split('> ' .. command .. '\\n' .. command_output, '\\n'), 'bash')\n00530| end\n00531| end\n00532| \n00533| ---@param output Output Output object to write to\n00534| ---@param tool_type string Tool type (e.g., 'read', 'edit', 'write')\n00535| ---@param input FileToolInput data for the tool\n00536| ---@param metadata FileToolMetadata Metadata for the tool use\n00537| function M._format_file_tool(output, tool_type, input, metadata)\n00538| local file_name = input and vim.fn.fnamemodify(input.filePath, ':t') or ''\n00539| local file_type = input and util.get_markdown_filetype(input.filePath) or ''\n00540| local tool_action_icons = { read = icons.get('read'), edit = icons.get('edit'), write = icons.get('write') }\n00541| \n00542| M._format_action(output, tool_action_icons[tool_type] .. ' ' .. tool_type, file_name)\n00543| \n00544| if not config.ui.output.tools.show_output then\n00545| return\n00546| end\n00547| \n00548| if tool_type == 'edit' and metadata.diff then\n00549| M._format_diff(output, metadata.diff, file_type)\n00550| elseif tool_type == 'write' and input and input.content then\n00551| M._format_code(output, vim.split(input.content, '\\n'), file_type)\n00552| end\n00553| end\n00554| \n00555| ---@param output Output Output object to write to\n00556| ---@param title string\n00557| ---@param input TodoToolInput\n00558| function M._format_todo_tool(output, title, input)\n00559| M._format_action(output, icons.get('plan') .. ' plan', (title or ''))\n00560| if not config.ui.output.tools.show_output then\n00561| return\n00562| end\n00563| \n00564| local todos = input and input.todos or {}\n00565| \n00566| for _, item in ipairs(todos) do\n00567| local statuses = { in_progress = '-', completed = 'x', pending = ' ' }\n00568| output:add_line(string.format('- [%s] %s ', statuses[item.status], item.content))\n00569| end\n00570| end\n00571| \n00572| ---@param output Output Output object to write to\n00573| ---@param input GlobToolInput data for the tool\n00574| ---@param metadata GlobToolMetadata Metadata for the tool use\n00575| function M._format_glob_tool(output, input, metadata)\n00576| M._format_action(output, icons.get('search') .. ' glob', input and input.pattern)\n00577| if not config.ui.output.tools.show_output then\n00578| return\n00579| end\n00580| local prefix = metadata.truncated and ' more than' or ''\n00581| output:add_line(string.format('Found%s `%d` file(s):', prefix, metadata.count or 0))\n00582| end\n00583| \n00584| ---@param output Output Output object to write to\n00585| ---@param input GrepToolInput data for the tool\n00586| ---@param metadata GrepToolMetadata Metadata for the tool use\n00587| function M._format_grep_tool(output, input, metadata)\n00588| input = input or { path = '', include = '', pattern = '' }\n00589| \n00590| local grep_str = string.format('%s` `%s', (input.path or input.include) or '', input.pattern or '')\n00591| \n00592| M._format_action(output, icons.get('search') .. ' grep', grep_str)\n00593| if not config.ui.output.tools.show_output then\n00594| return\n00595| end\n00596| local prefix = metadata.truncated and ' more than' or ''\n00597| output:add_line(\n00598| string.format('Found%s `%d` match' .. (metadata.matches ~= 1 and 'es' or ''), prefix, metadata.matches or 0)\n00599| )\n00600| end\n00601| \n00602| ---@param output Output Output object to write to\n00603| ---@param input WebFetchToolInput data for the tool\n00604| function M._format_webfetch_tool(output, input)\n00605| M._format_action(output, icons.get('web') .. ' fetch', input and input.url)\n00606| end\n00607| \n00608| ---@param output Output Output object to write to\n00609| ---@param input ListToolInput\n00610| ---@param metadata ListToolMetadata\n00611| ---@param tool_output string\n00612| function M._format_list_tool(output, input, metadata, tool_output)\n00613| M._format_action(output, icons.get('list') .. ' list', input and input.path or '')\n00614| if not config.ui.output.tools.show_output then\n00615| return\n00616| end\n00617| local lines = vim.split(vim.trim(tool_output or ''), '\\n')\n00618| if #lines < 1 or metadata.count == 0 then\n00619| output:add_line('No files found.')\n00620| return\n00621| end\n00622| if #lines > 1 then\n00623| output:add_line('Files:')\n00624| for i = 2, #lines do\n00625| local file = vim.trim(lines[i])\n00626| if file ~= '' then\n00627| output:add_line(' • ' .. file)\n00628| end\n00629| end\n00630| end\n00631| if metadata.truncated then\n00632| output:add_line(string.format('Results truncated, showing first %d files', metadata.count or '?'))\n00633| end\n00634| end\n00635| \n00636| ---@param output Output Output object to write to\n00637| ---@param part OpencodeMessagePart\n00638| function M._format_tool(output, part)\n00639| local tool = part.tool\n00640| if not tool or not part.state then\n00641| return\n00642| end\n00643| \n00644| local start_line = output:get_line_count() + 1\n00645| local input = part.state.input or {}\n00646| local metadata = part.state.metadata or {}\n00647| local tool_output = part.state.output or ''\n00648| \n00649| if state.current_permission and state.current_permission.messageID == part.messageID then\n00650| metadata = state.current_permission.metadata or metadata\n00651| end\n00652| \n00653| if tool == 'bash' then\n00654| M._format_bash_tool(output, input --[[@as BashToolInput]], metadata --[[@as BashToolMetadata]])\n00655| elseif tool == 'read' or tool == 'edit' or tool == 'write' then\n00656| M._format_file_tool(output, tool, input --[[@as FileToolInput]], metadata --[[@as FileToolMetadata]])\n00657| elseif tool == 'todowrite' then\n00658| M._format_todo_tool(output, part.state.title, input --[[@as TodoToolInput]])\n00659| elseif tool == 'glob' then\n00660| M._format_glob_tool(output, input --[[@as GlobToolInput]], metadata --[[@as GlobToolMetadata]])\n00661| elseif tool == 'list' then\n00662| M._format_list_tool(output, input --[[@as ListToolInput]], metadata --[[@as ListToolMetadata]], tool_output)\n00663| elseif tool == 'grep' then\n00664| M._format_grep_tool(output, input --[[@as GrepToolInput]], metadata --[[@as GrepToolMetadata]])\n00665| elseif tool == 'webfetch' then\n00666| M._format_webfetch_tool(output, input --[[@as WebFetchToolInput]])\n00667| elseif tool == 'task' then\n00668| M._format_task_tool(output, input --[[@as TaskToolInput]], metadata --[[@as TaskToolMetadata]], tool_output)\n00669| else\n00670| M._format_action(output, icons.get('tool') .. ' tool', tool)\n00671| end\n00672| \n00673| if part.state.status == 'error' and part.state.error then\n00674| output:add_line('')\n00675| M._format_callout(output, 'ERROR', part.state.error)\n00676| ---@diagnostic disable-next-line: undefined-field\n00677| elseif part.state.input and part.state.input.error then\n00678| output:add_line('')\n00679| ---I'm not sure about the type with state.input.error\n00680| ---@diagnostic disable-next-line: undefined-field\n00681| M._format_callout(output, 'ERROR', part.state.input.error)\n00682| end\n00683| \n00684| if\n00685| state.current_permission\n00686| and (\n00687| (\n00688| state.current_permission.tool\n00689| and state.current_permission.tool.callID == part.callID\n00690| and state.current_permission.tool.messageID == part.messageID\n00691| )\n00692| ---@TODO this is for backward compatibility, remove later\n00693| or (state.current_permission.messageID == part.messageID and state.current_permission.callID == part.callID)\n00694| )\n00695| then\n00696| M._handle_permission_request(output, part)\n00697| end\n00698| \n00699| local end_line = output:get_line_count()\n00700| if end_line - start_line > 1 then\n00701| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1)\n00702| end\n00703| end\n00704| \n00705| ---@param output Output Output object to write to\n00706| ---@param input TaskToolInput data for the tool\n00707| ---@param metadata TaskToolMetadata Metadata for the tool use\n00708| ---@param tool_output string\n00709| function M._format_task_tool(output, input, metadata, tool_output)\n00710| local start_line = output:get_line_count() + 1\n00711| M._format_action(output, icons.get('task') .. ' task', input and input.description)\n00712| \n00713| if config.ui.output.tools.show_output then\n00714| if tool_output and tool_output ~= '' then\n00715| output:add_empty_line()\n00716| output:add_lines(vim.split(tool_output, '\\n'))\n00717| output:add_empty_line()\n00718| end\n00719| \n00720| if metadata.summary and type(metadata.summary) == 'table' then\n00721| for _, sub_part in ipairs(metadata.summary) do\n00722| if sub_part.type == 'tool' and sub_part.tool then\n00723| M._format_tool(output, sub_part)\n00724| end\n00725| end\n00726| end\n00727| end\n00728| \n00729| local end_line = output:get_line_count()\n00730| output:add_action({\n00731| text = '[S]elect Child Session',\n00732| type = 'select_child_session',\n00733| args = {},\n00734| key = 'S',\n00735| display_line = start_line - 1,\n00736| range = { from = start_line, to = end_line },\n00737| })\n00738| end\n00739| \n00740| ---@param output Output Output object to write to\n00741| ---@param lines string[]\n00742| ---@param language string\n00743| function M._format_code(output, lines, language)\n00744| output:add_empty_line()\n00745| --- NOTE: use longer code fence because lines could contain ```\n00746| output:add_line('`````' .. (language or ''))\n00747| output:add_lines(util.sanitize_lines(lines))\n00748| output:add_line('`````')\n00749| end\n00750| \n00751| ---@param output Output Output object to write to\n00752| ---@param code string\n00753| ---@param file_type string\n00754| function M._format_diff(output, code, file_type)\n00755| output:add_empty_line()\n00756| \n00757| --- NOTE: use longer code fence because code could contain ```\n00758| output:add_line('`````' .. file_type)\n00759| local lines = vim.split(code, '\\n')\n00760| if #lines > 5 then\n00761| lines = vim.list_slice(lines, 6)\n00762| end\n00763| \n00764| for _, line in ipairs(lines) do\n00765| local first_char = line:sub(1, 1)\n00766| if first_char == '+' or first_char == '-' then\n00767| local hl_group = first_char == '+' and 'OpencodeDiffAdd' or 'OpencodeDiffDelete'\n00768| output:add_line(' ' .. line:sub(2))\n00769| local line_idx = output:get_line_count()\n00770| output:add_extmark(line_idx - 1, function()\n00771| return {\n00772| end_col = 0,\n00773| end_row = line_idx,\n00774| virt_text = { { first_char, hl_group } },\n00775| hl_group = hl_group,\n00776| hl_eol = true,\n00777| priority = 5000,\n00778| right_gravity = true,\n00779| end_right_gravity = false,\n00780| virt_text_hide = false,\n00781| virt_text_pos = 'overlay',\n00782| virt_text_repeat_linebreak = false,\n00783| }\n00784| end)\n00785| else\n00786| output:add_line(line)\n00787| end\n00788| end\n00789| output:add_line('`````')\n00790| end\n00791| \n00792| ---@param output Output Output object to write to\n00793| ---@param start_line number\n00794| ---@param end_line number\n00795| ---@param hl_group string Highlight group for the border character\n00796| ---@param win_col number\n00797| ---@param text_hl_group? string Optional highlight group for the background/foreground of text lines\n00798| function M._add_vertical_border(output, start_line, end_line, hl_group, win_col, text_hl_group)\n00799| for line = start_line, end_line do\n00800| local extmark_opts = {\n00801| virt_text = { { require('opencode.ui.icons').get('border'), hl_group } },\n00802| virt_text_pos = 'overlay',\n00803| virt_text_win_col = win_col,\n00804| virt_text_repeat_linebreak = true,\n00805| }\n00806| \n00807| -- Add line highlight if text_hl_group is provided\n00808| if text_hl_group then\n00809| extmark_opts.line_hl_group = text_hl_group\n00810| end\n00811| \n00812| output:add_extmark(line - 1, extmark_opts --[[@as OutputExtmark]])\n00813| end\n00814| end\n00815| \n00816| ---Formats a single message part and returns the resulting output object\n00817| ---@param part OpencodeMessagePart The part to format\n00818| ---@param message? OpencodeMessage Optional message object to extract role and mentions from\n00819| ---@param is_last_part? boolean Whether this is the last part in the message, used to show an error if there is one\n00820| ---@return Output\n00821| function M.format_part(part, message, is_last_part)\n00822| local output = Output.new()\n00823| \n00824| if not message or not message.info or not message.info.role then\n00825| return output\n00826| end\n00827| \n00828| local content_added = false\n00829| local role = message.info.role\n00830| \n00831| if role == 'user' then\n00832| if part.type == 'text' and part.text then\n00833| if part.synthetic == true then\n00834| M._format_selection_context(output, part)\n00835| M._format_cursor_data_context(output, part)\n00836| M._format_diagnostics_context(output, part)\n00837| else\n00838| M._format_user_prompt(output, vim.trim(part.text), message)\n00839| content_added = true\n00840| end\n00841| elseif part.type == 'file' then\n00842| local file_line = M._format_context_file(output, part.filename)\n00843| if file_line then\n00844| M._add_vertical_border(output, file_line - 1, file_line, 'OpencodeMessageRoleUser', -3)\n00845| content_added = true\n00846| end\n00847| end\n00848| elseif role == 'assistant' then\n00849| if part.type == 'text' and part.text then\n00850| M._format_assistant_message(output, vim.trim(part.text))\n00851| content_added = true\n00852| elseif part.type == 'reasoning' and part.text then\n00853| M._format_reasoning(output, part)\n00854| content_added = true\n00855| elseif part.type == 'tool' then\n00856| M._format_tool(output, part)\n00857| content_added = true\n00858| elseif part.type == 'patch' and part.hash then\n00859| M._format_patch(output, part)\n00860| content_added = true\n00861| end\n00862| end\n00863| \n00864| if content_added then\n00865| output:add_empty_line()\n00866| end\n00867| \n00868| if is_last_part and role == 'assistant' and message.info.error and message.info.error ~= '' then\n00869| local error = message.info.error\n00870| local error_message = error.data and error.data.message or vim.inspect(error)\n00871| M._format_callout(output, 'ERROR', error_message)\n00872| output:add_empty_line()\n00873| end\n00874| \n00875| return output\n00876| end\n00877| \n00878| return M\n00879| \n\n(End of file - total 879 lines)\n","synthetic":true}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"file","url":"file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua","id":"prt_b8e7c60a7002ybV09VDHoQQeO7","filename":"lua/opencode/ui/formatter.lua","messageID":"msg_b8e7c60a2001Kisjwk2mVB4dye","mime":"text/plain"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","id":"prt_b8e7c60a3002XHHlk77vAPApvR","messageID":"msg_b8e7c60a2001Kisjwk2mVB4dye","text":"{\"content\":[{\"msg\":\"expected `SessionRevertInfo` but found `SessionRevertInfo?`.\",\"severity\":2,\"pos\":\"l156:c68\"},{\"msg\":\"expected `integer?` but found `number`.\",\"severity\":2,\"pos\":\"l490:c43\"},{\"msg\":\"expected `integer` but found `number`.\",\"severity\":2,\"pos\":\"l492:c45\"},{\"msg\":\"expected `integer?` but found `number`.\",\"severity\":2,\"pos\":\"l492:c62\"},{\"msg\":\"state.active_session may be nil\",\"severity\":2,\"pos\":\"l156:c68\"},{\"msg\":\"state.messages[#state.messages] may be nil\",\"severity\":2,\"pos\":\"l272:c74\"},{\"msg\":\"state.messages may be nil\",\"severity\":2,\"pos\":\"l272:c74\"},{\"msg\":\"Undefined field `[diag.severity]`.\",\"severity\":2,\"pos\":\"l435:c42\"},{\"msg\":\"Undefined field `command`.\",\"severity\":2,\"pos\":\"l526:c34\"},{\"msg\":\"Undefined field `command`.\",\"severity\":2,\"pos\":\"l527:c47\"},{\"msg\":\"Cannot assign `number` to `integer`.\",\"severity\":2,\"pos\":\"l493:c5\"}],\"context_type\":\"diagnostics\"}","synthetic":true}},"type":"message.part.updated"},{"properties":{"info":{"title":"New session - 2026-01-05T14:07:52.149Z","version":"1.1.2","directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_47183a8abffeZzOLeJ3j2KV8f8","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","time":{"updated":1767622074603,"created":1767622072149}}},"type":"session.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"info":{"providerID":"github-copilot","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"agent":"build","time":{"created":1767622074609},"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","mode":"build","modelID":"gpt-4.1","id":"msg_b8e7c60f1001aEWYlAaDRXQ4aJ","parentID":"msg_b8e7c60a2001Kisjwk2mVB4dye","cost":0,"tokens":{"output":0,"reasoning":0,"input":0,"cache":{"write":0,"read":0}}}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","time":{"created":1767622074530},"model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"role":"user","id":"msg_b8e7c60a2001Kisjwk2mVB4dye","agent":"build","system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","summary":{"diffs":[]}}},"type":"message.updated"},{"properties":{"info":{"title":"New session - 2026-01-05T14:07:52.149Z","version":"1.1.2","directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_47183a8abffeZzOLeJ3j2KV8f8","time":{"updated":1767622074670,"created":1767622072149},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","summary":{"deletions":0,"additions":0,"files":0}}},"type":"session.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"step-start","id":"prt_b8e7c6672001F10WAiQKbzNEtE","snapshot":"5ba6e95774829e7f501299039b72b72dc32c6620","messageID":"msg_b8e7c60f1001aEWYlAaDRXQ4aJ"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"tool","messageID":"msg_b8e7c60f1001aEWYlAaDRXQ4aJ","id":"prt_b8e7c6686001cCV44vsFtbpF42","state":{"status":"pending","input":{},"raw":""},"callID":"call_KAC0LdAxKEbU6HTAPH5QJfGx","tool":"bash"}},"type":"message.part.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"tool","messageID":"msg_b8e7c60f1001aEWYlAaDRXQ4aJ","id":"prt_b8e7c6686001cCV44vsFtbpF42","state":{"status":"running","input":{"description":"Shows working tree status","command":"git status"},"time":{"start":1767622076189}},"callID":"call_KAC0LdAxKEbU6HTAPH5QJfGx","tool":"bash"}},"type":"message.part.updated"},{"properties":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","tool":{"messageID":"msg_b8e7c60f1001aEWYlAaDRXQ4aJ","callID":"call_KAC0LdAxKEbU6HTAPH5QJfGx"},"patterns":["git status"],"id":"per_b8e7c6744001DX6EZ9KHM15RLi","permission":"bash","always":["git status*"],"metadata":{}},"type":"permission.asked"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"info":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","time":{"created":1767622074530},"model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"role":"user","id":"msg_b8e7c60a2001Kisjwk2mVB4dye","agent":"build","system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","summary":{"title":"Running git status to list changed files","diffs":[]}}},"type":"message.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"info":{"title":"Running git status for formatter.lua changes","version":"1.1.2","directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_47183a8abffeZzOLeJ3j2KV8f8","time":{"updated":1767622082619,"created":1767622072149},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","summary":{"deletions":0,"additions":0,"files":0}}},"type":"session.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","requestID":"per_b8e7c6744001DX6EZ9KHM15RLi","reply":"once"},"type":"permission.replied"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"tool","messageID":"msg_b8e7c60f1001aEWYlAaDRXQ4aJ","id":"prt_b8e7c6686001cCV44vsFtbpF42","state":{"title":"Shows working tree status","input":{"description":"Shows working tree status","command":"git status"},"output":"On branch main\nYour branch is up to date with 'origin/main'.\n\nChanges not staged for commit:\n (use \"git add ...\" to update what will be committed)\n (use \"git restore ...\" to discard changes in working directory)\n\tmodified: lua/opencode/event_manager.lua\n\tmodified: lua/opencode/ui/formatter.lua\n\tmodified: lua/opencode/ui/renderer.lua\n\nUntracked files:\n (use \"git add ...\" to include in what will be committed)\n\ttest.lua\n\ttests/data/permission_ask_new.json\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n","status":"completed","metadata":{"exit":0,"description":"Shows working tree status","output":"On branch main\nYour branch is up to date with 'origin/main'.\n\nChanges not staged for commit:\n (use \"git add ...\" to update what will be committed)\n (use \"git restore ...\" to discard changes in working directory)\n\tmodified: lua/opencode/event_manager.lua\n\tmodified: lua/opencode/ui/formatter.lua\n\tmodified: lua/opencode/ui/renderer.lua\n\nUntracked files:\n (use \"git add ...\" to include in what will be committed)\n\ttest.lua\n\ttests/data/permission_ask_new.json\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n"},"time":{"start":1767622076189,"end":1767622106719}},"callID":"call_KAC0LdAxKEbU6HTAPH5QJfGx","tool":"bash"}},"type":"message.part.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"step-finish","messageID":"msg_b8e7c60f1001aEWYlAaDRXQ4aJ","id":"prt_b8e7cde62001EgRfgQpjNPuSc8","reason":"tool-calls","cost":0,"snapshot":"34a4eef77f714f2e3a282c410dbda315c4781fee","tokens":{"output":23,"reasoning":0,"input":10887,"cache":{"write":0,"read":9984}}}},"type":"message.part.updated"},{"properties":{"info":{"providerID":"github-copilot","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"agent":"build","finish":"tool-calls","time":{"created":1767622074609},"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","mode":"build","modelID":"gpt-4.1","id":"msg_b8e7c60f1001aEWYlAaDRXQ4aJ","parentID":"msg_b8e7c60a2001Kisjwk2mVB4dye","cost":0,"tokens":{"output":23,"reasoning":0,"input":10887,"cache":{"write":0,"read":9984}}}},"type":"message.updated"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"patch","id":"prt_b8e7cde8f001JcNpZEALOVaZnq","hash":"5ba6e95774829e7f501299039b72b72dc32c6620","messageID":"msg_b8e7c60f1001aEWYlAaDRXQ4aJ","files":["/home/francis/Projects/_nvim/opencode.nvim/tests/data/permission_ask_new.json"]}},"type":"message.part.updated"},{"properties":{"info":{"providerID":"github-copilot","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"agent":"build","finish":"tool-calls","time":{"created":1767622074609,"completed":1767622106776},"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","mode":"build","modelID":"gpt-4.1","id":"msg_b8e7c60f1001aEWYlAaDRXQ4aJ","parentID":"msg_b8e7c60a2001Kisjwk2mVB4dye","cost":0,"tokens":{"output":23,"reasoning":0,"input":10887,"cache":{"write":0,"read":9984}}}},"type":"message.updated"},{"properties":{"info":{"providerID":"github-copilot","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"agent":"build","time":{"created":1767622106782},"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","mode":"build","modelID":"gpt-4.1","id":"msg_b8e7cde9e0013hRkUyt0X2yMil","parentID":"msg_b8e7c60a2001Kisjwk2mVB4dye","cost":0,"tokens":{"output":0,"reasoning":0,"input":0,"cache":{"write":0,"read":0}}}},"type":"message.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"info":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","time":{"created":1767622074530},"model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"role":"user","id":"msg_b8e7c60a2001Kisjwk2mVB4dye","agent":"build","system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","summary":{"title":"Running git status to list changed files","diffs":[{"file":"tests/data/permission_ask_new.json","after":"[{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"time\":{\"updated\":1767622072149,\"created\":1767622072149}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"time\":{\"created\":1767622074530}}},\"type\":\"message.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3001M2zsH9REfPdlQt\",\"text\":\"@no-trust run a git status and tell me what files are changed\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3003Ta9NcXkN0lb0lF\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"Called the Read tool with the following input: {\\\"filePath\\\":\\\"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\\\"}\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a7001d3WhKOu2vCR4Cf\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"\\n00001| local context_module = require('opencode.context')\\n00002| local icons = require('opencode.ui.icons')\\n00003| local util = require('opencode.util')\\n00004| local Output = require('opencode.ui.output')\\n00005| local state = require('opencode.state')\\n00006| local config = require('opencode.config')\\n00007| local snapshot = require('opencode.snapshot')\\n00008| local mention = require('opencode.ui.mention')\\n00009| \\n00010| local M = {}\\n00011| \\n00012| M.separator = {\\n00013| '----',\\n00014| '',\\n00015| }\\n00016| \\n00017| ---@param output Output\\n00018| ---@param part OpencodeMessagePart\\n00019| function M._format_reasoning(output, part)\\n00020| local text = vim.trim(part.text or '')\\n00021| if text == '' then\\n00022| return\\n00023| end\\n00024| \\n00025| local start_line = output:get_line_count() + 1\\n00026| \\n00027| local title = 'Reasoning'\\n00028| local time = part.time\\n00029| if time and type(time) == 'table' and time.start then\\n00030| local start_text = util.format_time(time.start) or ''\\n00031| local end_text = (time['end'] and util.format_time(time['end'])) or nil\\n00032| if end_text and end_text ~= '' then\\n00033| title = string.format('%s (%s - %s)', title, start_text, end_text)\\n00034| elseif start_text ~= '' then\\n00035| title = string.format('%s (%s)', title, start_text)\\n00036| end\\n00037| end\\n00038| \\n00039| M._format_action(output, icons.get('reasoning') .. ' ' .. title, '')\\n00040| \\n00041| if config.ui.output.tools.show_reasoning_output then\\n00042| output:add_empty_line()\\n00043| output:add_lines(vim.split(text, '\\\\n'))\\n00044| output:add_empty_line()\\n00045| end\\n00046| \\n00047| local end_line = output:get_line_count()\\n00048| if end_line - start_line > 1 then\\n00049| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1, 'OpencodeReasoningText')\\n00050| else\\n00051| output:add_extmark(start_line - 1, {\\n00052| line_hl_group = 'OpencodeReasoningText',\\n00053| } --[[@as OutputExtmark]])\\n00054| end\\n00055| end\\n00056| \\n00057| function M._handle_permission_request(output, part)\\n00058| if part.state and part.state.status == 'error' and part.state.error then\\n00059| if part.state.error:match('rejected permission') then\\n00060| state.current_permission = nil\\n00061| else\\n00062| vim.notify('Unknown part state error: ' .. part.state.error)\\n00063| end\\n00064| return\\n00065| end\\n00066| \\n00067| M._format_permission_request(output)\\n00068| end\\n00069| \\n00070| function M._format_permission_request(output)\\n00071| local keys\\n00072| \\n00073| if require('opencode.ui.ui').is_opencode_focused() then\\n00074| keys = {\\n00075| config.keymap.permission.accept,\\n00076| config.keymap.permission.accept_all,\\n00077| config.keymap.permission.deny,\\n00078| }\\n00079| else\\n00080| keys = {\\n00081| config.get_key_for_function('editor', 'permission_accept'),\\n00082| config.get_key_for_function('editor', 'permission_accept_all'),\\n00083| config.get_key_for_function('editor', 'permission_deny'),\\n00084| }\\n00085| end\\n00086| \\n00087| output:add_empty_line()\\n00088| output:add_line('> [!WARNING] Permission required to run this tool.')\\n00089| output:add_line('>')\\n00090| output:add_line(('> Accept `%s` Always `%s` Deny `%s`'):format(unpack(keys)))\\n00091| output:add_empty_line()\\n00092| end\\n00093| \\n00094| ---Calculate statistics for reverted messages and tool calls\\n00095| ---@param messages {info: MessageInfo, parts: OpencodeMessagePart[]}[] All messages in the session\\n00096| ---@param revert_index number Index of the message where revert occurred\\n00097| ---@param revert_info SessionRevertInfo Revert information\\n00098| ---@return {messages: number, tool_calls: number, files: table}\\n00099| function M._calculate_revert_stats(messages, revert_index, revert_info)\\n00100| local stats = {\\n00101| messages = 0,\\n00102| tool_calls = 0,\\n00103| files = {}, -- { [filename] = { additions = n, deletions = m } }\\n00104| }\\n00105| \\n00106| for i = revert_index, #messages do\\n00107| local msg = messages[i]\\n00108| if msg.info.role == 'user' then\\n00109| stats.messages = stats.messages + 1\\n00110| end\\n00111| if msg.parts then\\n00112| for _, part in ipairs(msg.parts) do\\n00113| if part.type == 'tool' then\\n00114| stats.tool_calls = stats.tool_calls + 1\\n00115| end\\n00116| end\\n00117| end\\n00118| end\\n00119| \\n00120| if revert_info.diff then\\n00121| local current_file = nil\\n00122| for line in revert_info.diff:gmatch('[^\\\\r\\\\n]+') do\\n00123| local file_a = line:match('^%-%-%- ([ab]/.+)')\\n00124| local file_b = line:match('^%+%+%+ ([ab]/.+)')\\n00125| if file_b then\\n00126| current_file = file_b:gsub('^[ab]/', '')\\n00127| if not stats.files[current_file] then\\n00128| stats.files[current_file] = { additions = 0, deletions = 0 }\\n00129| end\\n00130| elseif file_a then\\n00131| current_file = file_a:gsub('^[ab]/', '')\\n00132| if not stats.files[current_file] then\\n00133| stats.files[current_file] = { additions = 0, deletions = 0 }\\n00134| end\\n00135| elseif line:sub(1, 1) == '+' and not line:match('^%+%+%+') then\\n00136| if current_file then\\n00137| stats.files[current_file].additions = stats.files[current_file].additions + 1\\n00138| end\\n00139| elseif line:sub(1, 1) == '-' and not line:match('^%-%-%-') then\\n00140| if current_file then\\n00141| stats.files[current_file].deletions = stats.files[current_file].deletions + 1\\n00142| end\\n00143| end\\n00144| end\\n00145| end\\n00146| \\n00147| return stats\\n00148| end\\n00149| \\n00150| ---Format the revert callout with statistics\\n00151| ---@param session_data OpencodeMessage[] All messages in the session\\n00152| ---@param start_idx number Index of the message where revert occurred\\n00153| ---@return Output output object representing the lines, extmarks, and actions\\n00154| function M._format_revert_message(session_data, start_idx)\\n00155| local output = Output.new()\\n00156| local stats = M._calculate_revert_stats(session_data, start_idx, state.active_session.revert)\\n00157| local message_text = stats.messages == 1 and 'message' or 'messages'\\n00158| local tool_text = stats.tool_calls == 1 and 'tool call' or 'tool calls'\\n00159| \\n00160| output:add_lines(M.separator)\\n00161| output:add_line(\\n00162| string.format('> %d %s reverted, %d %s reverted', stats.messages, message_text, stats.tool_calls, tool_text)\\n00163| )\\n00164| output:add_line('>')\\n00165| output:add_line('> type `/redo` to restore.')\\n00166| output:add_empty_line()\\n00167| \\n00168| if stats.files and next(stats.files) then\\n00169| for file, fstats in pairs(stats.files) do\\n00170| local file_diff = {}\\n00171| if fstats.additions > 0 then\\n00172| table.insert(file_diff, '+' .. fstats.additions)\\n00173| end\\n00174| if fstats.deletions > 0 then\\n00175| table.insert(file_diff, '-' .. fstats.deletions)\\n00176| end\\n00177| if #file_diff > 0 then\\n00178| local line_str = string.format(icons.get('file') .. '%s: %s', file, table.concat(file_diff, ' '))\\n00179| local line_idx = output:add_line(line_str)\\n00180| local col = #(' ' .. file .. ': ')\\n00181| for _, diff in ipairs(file_diff) do\\n00182| local hl_group = diff:sub(1, 1) == '+' and 'OpencodeDiffAddText' or 'OpencodeDiffDeleteText'\\n00183| output:add_extmark(line_idx - 1, {\\n00184| virt_text = { { diff, hl_group } },\\n00185| virt_text_pos = 'inline',\\n00186| virt_text_win_col = col,\\n00187| priority = 1000,\\n00188| } --[[@as OutputExtmark]])\\n00189| col = col + #diff + 1\\n00190| end\\n00191| end\\n00192| end\\n00193| end\\n00194| return output\\n00195| end\\n00196| \\n00197| local function add_action(output, text, action_type, args, key, line)\\n00198| -- actions use api-indexing (e.g. 0 indexed)\\n00199| line = (line or output:get_line_count()) - 1\\n00200| output:add_action({\\n00201| text = text,\\n00202| type = action_type,\\n00203| args = args,\\n00204| key = key,\\n00205| display_line = line,\\n00206| range = { from = line, to = line },\\n00207| })\\n00208| end\\n00209| \\n00210| ---@param output Output Output object to write to\\n00211| ---@param part OpencodeMessagePart\\n00212| function M._format_patch(output, part)\\n00213| if not part.hash then\\n00214| return\\n00215| end\\n00216| \\n00217| local restore_points = snapshot.get_restore_points_by_parent(part.hash) or {}\\n00218| M._format_action(output, icons.get('snapshot') .. ' Created Snapshot', vim.trim(part.hash:sub(1, 8)))\\n00219| \\n00220| -- Anchor all snapshot-level actions to the snapshot header line\\n00221| add_action(output, '[R]evert file', 'diff_revert_selected_file', { part.hash }, 'R')\\n00222| add_action(output, 'Revert [A]ll', 'diff_revert_all', { part.hash }, 'A')\\n00223| add_action(output, '[D]iff', 'diff_open', { part.hash }, 'D')\\n00224| \\n00225| if #restore_points > 0 then\\n00226| for _, restore_point in ipairs(restore_points) do\\n00227| output:add_line(\\n00228| string.format(\\n00229| ' %s Restore point `%s` - %s ',\\n00230| icons.get('restore_point'),\\n00231| vim.trim(restore_point.id:sub(1, 8)),\\n00232| util.format_time(restore_point.created_at)\\n00233| )\\n00234| )\\n00235| add_action(output, 'Restore [A]ll', 'diff_restore_snapshot_all', { restore_point.id }, 'A')\\n00236| add_action(output, '[R]estore file', 'diff_restore_snapshot_file', { restore_point.id }, 'R')\\n00237| end\\n00238| end\\n00239| end\\n00240| \\n00241| ---@param output Output Output object to write to\\n00242| ---@param message MessageInfo\\n00243| function M._format_error(output, message)\\n00244| output:add_empty_line()\\n00245| M._format_callout(output, 'ERROR', vim.inspect(message.error))\\n00246| end\\n00247| \\n00248| ---@param message OpencodeMessage\\n00249| ---@return Output\\n00250| function M.format_message_header(message)\\n00251| local output = Output.new()\\n00252| \\n00253| output:add_lines(M.separator)\\n00254| local role = message.info.role or 'unknown'\\n00255| local icon = message.info.role == 'user' and icons.get('header_user') or icons.get('header_assistant')\\n00256| \\n00257| local time = message.info.time and message.info.time.created or nil\\n00258| local time_text = (time and ' (' .. util.format_time(time) .. ')' or '')\\n00259| local role_hl = 'OpencodeMessageRole' .. role:sub(1, 1):upper() .. role:sub(2)\\n00260| local model_text = message.info.modelID and ' ' .. message.info.modelID or ''\\n00261| \\n00262| local debug_text = config.debug.show_ids and ' [' .. message.info.id .. ']' or ''\\n00263| \\n00264| local display_name\\n00265| if role == 'assistant' then\\n00266| local mode = message.info.mode\\n00267| if mode and mode ~= '' then\\n00268| display_name = mode:upper()\\n00269| else\\n00270| -- For the most recent assistant message, show current_mode if mode is missing\\n00271| -- This handles new messages that haven't been stamped yet\\n00272| local is_last_message = #state.messages == 0 or message.info.id == state.messages[#state.messages].info.id\\n00273| if is_last_message and state.current_mode and state.current_mode ~= '' then\\n00274| display_name = state.current_mode:upper()\\n00275| else\\n00276| display_name = 'ASSISTANT'\\n00277| end\\n00278| end\\n00279| else\\n00280| display_name = role:upper()\\n00281| end\\n00282| \\n00283| output:add_extmark(output:get_line_count() - 1, {\\n00284| virt_text = {\\n00285| { icon, role_hl },\\n00286| { ' ' },\\n00287| { display_name, role_hl },\\n00288| { model_text, 'OpencodeHint' },\\n00289| { time_text, 'OpencodeHint' },\\n00290| { debug_text, 'OpencodeHint' },\\n00291| },\\n00292| virt_text_win_col = -3,\\n00293| priority = 10,\\n00294| } --[[@as OutputExtmark]])\\n00295| \\n00296| -- Only want to show the error if we have no parts. If we have parts, they'll\\n00297| -- handle rendering the error\\n00298| if\\n00299| role == 'assistant'\\n00300| and message.info.error\\n00301| and message.info.error ~= ''\\n00302| and (not message.parts or #message.parts == 0)\\n00303| then\\n00304| local error = message.info.error\\n00305| local error_message = error.data and error.data.message or vim.inspect(error)\\n00306| \\n00307| output:add_line('')\\n00308| M._format_callout(output, 'ERROR', error_message)\\n00309| end\\n00310| \\n00311| output:add_line('')\\n00312| return output\\n00313| end\\n00314| \\n00315| ---@param output Output Output object to write to\\n00316| ---@param callout string Callout type (e.g., 'ERROR', 'TODO')\\n00317| ---@param text string Callout text content\\n00318| ---@param title? string Optional title for the callout\\n00319| function M._format_callout(output, callout, text, title)\\n00320| title = title and title .. ' ' or ''\\n00321| local win_width = (state.windows and state.windows.output_win and vim.api.nvim_win_is_valid(state.windows.output_win))\\n00322| and vim.api.nvim_win_get_width(state.windows.output_win)\\n00323| or config.ui.window_width\\n00324| or 80\\n00325| if #text > win_width - 4 then\\n00326| local ok, substituted = pcall(vim.fn.substitute, text, '\\\\v(.{' .. (win_width - 8) .. '})', '\\\\1\\\\n', 'g')\\n00327| text = ok and substituted or text\\n00328| end\\n00329| \\n00330| -- Trim off any trailing newlines so there isn't an extra line in the\\n00331| -- extmarks section\\n00332| local lines = vim.split(text:gsub('\\\\n$', ''), '\\\\n')\\n00333| if #lines == 1 and title == '' then\\n00334| output:add_line('> [!' .. callout .. '] ' .. lines[1])\\n00335| else\\n00336| output:add_line('> [!' .. callout .. ']' .. title)\\n00337| output:add_line('>')\\n00338| output:add_lines(lines, '> ')\\n00339| end\\n00340| end\\n00341| \\n00342| ---@param output Output Output object to write to\\n00343| ---@param text string\\n00344| ---@param message? OpencodeMessage Optional message object to extract mentions from\\n00345| function M._format_user_prompt(output, text, message)\\n00346| local start_line = output:get_line_count()\\n00347| \\n00348| output:add_lines(vim.split(text, '\\\\n'))\\n00349| \\n00350| local end_line = output:get_line_count()\\n00351| \\n00352| local end_line_extmark_offset = 0\\n00353| \\n00354| local mentions = {}\\n00355| if message and message.parts then\\n00356| -- message.parts will only be filled out on a re-render\\n00357| -- we need to collect the mentions here\\n00358| for _, part in ipairs(message.parts) do\\n00359| if part.type == 'file' then\\n00360| -- we're rerendering this part and we have files, the space after the user prompt\\n00361| -- also needs an extmark\\n00362| end_line_extmark_offset = 1\\n00363| if part.source and part.source.text then\\n00364| table.insert(mentions, part.source.text)\\n00365| end\\n00366| elseif part.type == 'agent' then\\n00367| if part.source then\\n00368| table.insert(mentions, part.source)\\n00369| end\\n00370| end\\n00371| end\\n00372| end\\n00373| \\n00374| if #mentions > 0 then\\n00375| mention.highlight_mentions_in_output(output, text, mentions, start_line)\\n00376| end\\n00377| \\n00378| M._add_vertical_border(output, start_line, end_line + end_line_extmark_offset, 'OpencodeMessageRoleUser', -3)\\n00379| end\\n00380| \\n00381| ---@param output Output Output object to write to\\n00382| ---@param part OpencodeMessagePart\\n00383| function M._format_selection_context(output, part)\\n00384| local json = context_module.decode_json_context(part.text or '', 'selection')\\n00385| if not json then\\n00386| return\\n00387| end\\n00388| local start_line = output:get_line_count()\\n00389| output:add_lines(vim.split(json.content or '', '\\\\n'))\\n00390| output:add_empty_line()\\n00391| \\n00392| local end_line = output:get_line_count()\\n00393| \\n00394| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00395| end\\n00396| \\n00397| ---@param output Output Output object to write to\\n00398| ---@param part OpencodeMessagePart\\n00399| function M._format_cursor_data_context(output, part)\\n00400| local json = context_module.decode_json_context(part.text or '', 'cursor-data')\\n00401| if not json then\\n00402| return\\n00403| end\\n00404| local start_line = output:get_line_count()\\n00405| output:add_line('Line ' .. json.line .. ':')\\n00406| output:add_lines(vim.split(json.line_content or '', '\\\\n'))\\n00407| output:add_empty_line()\\n00408| \\n00409| local end_line = output:get_line_count()\\n00410| \\n00411| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00412| end\\n00413| \\n00414| ---@param output Output Output object to write to\\n00415| ---@param part OpencodeMessagePart\\n00416| function M._format_diagnostics_context(output, part)\\n00417| local json = context_module.decode_json_context(part.text or '', 'diagnostics')\\n00418| if not json then\\n00419| return\\n00420| end\\n00421| local start_line = output:get_line_count()\\n00422| local diagnostics = json.content --[[@as OpencodeDiagnostic[] ]]\\n00423| if not diagnostics or type(diagnostics) ~= 'table' or #diagnostics == 0 then\\n00424| return\\n00425| end\\n00426| \\n00427| local diagnostics_count = { error = 0, warn = 0, info = 0 }\\n00428| local diagnostics_icons = {\\n00429| error = icons.get('error'),\\n00430| warn = icons.get('warning'),\\n00431| info = icons.get('info'),\\n00432| }\\n00433| \\n00434| for _, diag in ipairs(diagnostics) do\\n00435| local name = vim.diagnostic.severity[diag.severity]:lower()\\n00436| diagnostics_count[name] = diagnostics_count[name] + 1\\n00437| end\\n00438| \\n00439| local diag_line = '**Diagnostics:**'\\n00440| for name, count in pairs(diagnostics_count) do\\n00441| if count > 0 then\\n00442| diag_line = diag_line .. (string.format(' %s(%d)', diagnostics_icons[name], count))\\n00443| end\\n00444| end\\n00445| output:add_line(diag_line)\\n00446| output:add_empty_line()\\n00447| local end_line = output:get_line_count()\\n00448| \\n00449| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00450| end\\n00451| \\n00452| ---Format and display the file path in the context\\n00453| ---@param output Output Output object to write to\\n00454| ---@param path string|nil File path\\n00455| function M._format_context_file(output, path)\\n00456| if not path or path == '' then\\n00457| return\\n00458| end\\n00459| local cwd = vim.fn.getcwd()\\n00460| if vim.startswith(path, cwd) then\\n00461| path = path:sub(#cwd + 2)\\n00462| end\\n00463| return output:add_line(string.format('[%s](%s)', path, path))\\n00464| end\\n00465| \\n00466| ---@param output Output Output object to write to\\n00467| ---@param text string\\n00468| function M._format_assistant_message(output, text)\\n00469| local reference_picker = require('opencode.ui.reference_picker')\\n00470| local references = reference_picker.parse_references(text, '')\\n00471| \\n00472| -- If no references, just add the text as-is\\n00473| if #references == 0 then\\n00474| output:add_lines(vim.split(text, '\\\\n'))\\n00475| return\\n00476| end\\n00477| \\n00478| -- Sort references by match_start position (ascending)\\n00479| table.sort(references, function(a, b)\\n00480| return a.match_start < b.match_start\\n00481| end)\\n00482| \\n00483| -- Build a new text with icons inserted before each reference\\n00484| local result = ''\\n00485| local last_pos = 1\\n00486| local ref_icon = icons.get('reference')\\n00487| \\n00488| for _, ref in ipairs(references) do\\n00489| -- Add text before this reference\\n00490| result = result .. text:sub(last_pos, ref.match_start - 1)\\n00491| -- Add the icon and the reference\\n00492| result = result .. ref_icon .. text:sub(ref.match_start, ref.match_end)\\n00493| last_pos = ref.match_end + 1\\n00494| end\\n00495| \\n00496| -- Add any remaining text after the last reference\\n00497| if last_pos <= #text then\\n00498| result = result .. text:sub(last_pos)\\n00499| end\\n00500| \\n00501| output:add_lines(vim.split(result, '\\\\n'))\\n00502| end\\n00503| \\n00504| ---@param output Output Output object to write to\\n00505| ---@param tool_type string Tool type (e.g., 'run', 'read', 'edit', etc.)\\n00506| ---@param value string Value associated with the action (e.g., filename, command)\\n00507| function M._format_action(output, tool_type, value)\\n00508| if not tool_type or not value then\\n00509| return\\n00510| end\\n00511| local line = string.format('**%s** %s', tool_type, value and #value > 0 and ('`' .. value .. '`') or '')\\n00512| \\n00513| output:add_line(line)\\n00514| end\\n00515| \\n00516| ---@param output Output Output object to write to\\n00517| ---@param input BashToolInput data for the tool\\n00518| ---@param metadata BashToolMetadata Metadata for the tool use\\n00519| function M._format_bash_tool(output, input, metadata)\\n00520| M._format_action(output, icons.get('run') .. ' run', input and input.description)\\n00521| \\n00522| if not config.ui.output.tools.show_output then\\n00523| return\\n00524| end\\n00525| \\n00526| if metadata.output or metadata.command or input.command then\\n00527| local command = input.command or metadata.command or ''\\n00528| local command_output = metadata.output and metadata.output ~= '' and ('\\\\n' .. metadata.output) or ''\\n00529| M._format_code(output, vim.split('> ' .. command .. '\\\\n' .. command_output, '\\\\n'), 'bash')\\n00530| end\\n00531| end\\n00532| \\n00533| ---@param output Output Output object to write to\\n00534| ---@param tool_type string Tool type (e.g., 'read', 'edit', 'write')\\n00535| ---@param input FileToolInput data for the tool\\n00536| ---@param metadata FileToolMetadata Metadata for the tool use\\n00537| function M._format_file_tool(output, tool_type, input, metadata)\\n00538| local file_name = input and vim.fn.fnamemodify(input.filePath, ':t') or ''\\n00539| local file_type = input and util.get_markdown_filetype(input.filePath) or ''\\n00540| local tool_action_icons = { read = icons.get('read'), edit = icons.get('edit'), write = icons.get('write') }\\n00541| \\n00542| M._format_action(output, tool_action_icons[tool_type] .. ' ' .. tool_type, file_name)\\n00543| \\n00544| if not config.ui.output.tools.show_output then\\n00545| return\\n00546| end\\n00547| \\n00548| if tool_type == 'edit' and metadata.diff then\\n00549| M._format_diff(output, metadata.diff, file_type)\\n00550| elseif tool_type == 'write' and input and input.content then\\n00551| M._format_code(output, vim.split(input.content, '\\\\n'), file_type)\\n00552| end\\n00553| end\\n00554| \\n00555| ---@param output Output Output object to write to\\n00556| ---@param title string\\n00557| ---@param input TodoToolInput\\n00558| function M._format_todo_tool(output, title, input)\\n00559| M._format_action(output, icons.get('plan') .. ' plan', (title or ''))\\n00560| if not config.ui.output.tools.show_output then\\n00561| return\\n00562| end\\n00563| \\n00564| local todos = input and input.todos or {}\\n00565| \\n00566| for _, item in ipairs(todos) do\\n00567| local statuses = { in_progress = '-', completed = 'x', pending = ' ' }\\n00568| output:add_line(string.format('- [%s] %s ', statuses[item.status], item.content))\\n00569| end\\n00570| end\\n00571| \\n00572| ---@param output Output Output object to write to\\n00573| ---@param input GlobToolInput data for the tool\\n00574| ---@param metadata GlobToolMetadata Metadata for the tool use\\n00575| function M._format_glob_tool(output, input, metadata)\\n00576| M._format_action(output, icons.get('search') .. ' glob', input and input.pattern)\\n00577| if not config.ui.output.tools.show_output then\\n00578| return\\n00579| end\\n00580| local prefix = metadata.truncated and ' more than' or ''\\n00581| output:add_line(string.format('Found%s `%d` file(s):', prefix, metadata.count or 0))\\n00582| end\\n00583| \\n00584| ---@param output Output Output object to write to\\n00585| ---@param input GrepToolInput data for the tool\\n00586| ---@param metadata GrepToolMetadata Metadata for the tool use\\n00587| function M._format_grep_tool(output, input, metadata)\\n00588| input = input or { path = '', include = '', pattern = '' }\\n00589| \\n00590| local grep_str = string.format('%s` `%s', (input.path or input.include) or '', input.pattern or '')\\n00591| \\n00592| M._format_action(output, icons.get('search') .. ' grep', grep_str)\\n00593| if not config.ui.output.tools.show_output then\\n00594| return\\n00595| end\\n00596| local prefix = metadata.truncated and ' more than' or ''\\n00597| output:add_line(\\n00598| string.format('Found%s `%d` match' .. (metadata.matches ~= 1 and 'es' or ''), prefix, metadata.matches or 0)\\n00599| )\\n00600| end\\n00601| \\n00602| ---@param output Output Output object to write to\\n00603| ---@param input WebFetchToolInput data for the tool\\n00604| function M._format_webfetch_tool(output, input)\\n00605| M._format_action(output, icons.get('web') .. ' fetch', input and input.url)\\n00606| end\\n00607| \\n00608| ---@param output Output Output object to write to\\n00609| ---@param input ListToolInput\\n00610| ---@param metadata ListToolMetadata\\n00611| ---@param tool_output string\\n00612| function M._format_list_tool(output, input, metadata, tool_output)\\n00613| M._format_action(output, icons.get('list') .. ' list', input and input.path or '')\\n00614| if not config.ui.output.tools.show_output then\\n00615| return\\n00616| end\\n00617| local lines = vim.split(vim.trim(tool_output or ''), '\\\\n')\\n00618| if #lines < 1 or metadata.count == 0 then\\n00619| output:add_line('No files found.')\\n00620| return\\n00621| end\\n00622| if #lines > 1 then\\n00623| output:add_line('Files:')\\n00624| for i = 2, #lines do\\n00625| local file = vim.trim(lines[i])\\n00626| if file ~= '' then\\n00627| output:add_line(' • ' .. file)\\n00628| end\\n00629| end\\n00630| end\\n00631| if metadata.truncated then\\n00632| output:add_line(string.format('Results truncated, showing first %d files', metadata.count or '?'))\\n00633| end\\n00634| end\\n00635| \\n00636| ---@param output Output Output object to write to\\n00637| ---@param part OpencodeMessagePart\\n00638| function M._format_tool(output, part)\\n00639| local tool = part.tool\\n00640| if not tool or not part.state then\\n00641| return\\n00642| end\\n00643| \\n00644| local start_line = output:get_line_count() + 1\\n00645| local input = part.state.input or {}\\n00646| local metadata = part.state.metadata or {}\\n00647| local tool_output = part.state.output or ''\\n00648| \\n00649| if state.current_permission and state.current_permission.messageID == part.messageID then\\n00650| metadata = state.current_permission.metadata or metadata\\n00651| end\\n00652| \\n00653| if tool == 'bash' then\\n00654| M._format_bash_tool(output, input --[[@as BashToolInput]], metadata --[[@as BashToolMetadata]])\\n00655| elseif tool == 'read' or tool == 'edit' or tool == 'write' then\\n00656| M._format_file_tool(output, tool, input --[[@as FileToolInput]], metadata --[[@as FileToolMetadata]])\\n00657| elseif tool == 'todowrite' then\\n00658| M._format_todo_tool(output, part.state.title, input --[[@as TodoToolInput]])\\n00659| elseif tool == 'glob' then\\n00660| M._format_glob_tool(output, input --[[@as GlobToolInput]], metadata --[[@as GlobToolMetadata]])\\n00661| elseif tool == 'list' then\\n00662| M._format_list_tool(output, input --[[@as ListToolInput]], metadata --[[@as ListToolMetadata]], tool_output)\\n00663| elseif tool == 'grep' then\\n00664| M._format_grep_tool(output, input --[[@as GrepToolInput]], metadata --[[@as GrepToolMetadata]])\\n00665| elseif tool == 'webfetch' then\\n00666| M._format_webfetch_tool(output, input --[[@as WebFetchToolInput]])\\n00667| elseif tool == 'task' then\\n00668| M._format_task_tool(output, input --[[@as TaskToolInput]], metadata --[[@as TaskToolMetadata]], tool_output)\\n00669| else\\n00670| M._format_action(output, icons.get('tool') .. ' tool', tool)\\n00671| end\\n00672| \\n00673| if part.state.status == 'error' and part.state.error then\\n00674| output:add_line('')\\n00675| M._format_callout(output, 'ERROR', part.state.error)\\n00676| ---@diagnostic disable-next-line: undefined-field\\n00677| elseif part.state.input and part.state.input.error then\\n00678| output:add_line('')\\n00679| ---I'm not sure about the type with state.input.error\\n00680| ---@diagnostic disable-next-line: undefined-field\\n00681| M._format_callout(output, 'ERROR', part.state.input.error)\\n00682| end\\n00683| \\n00684| if\\n00685| state.current_permission\\n00686| and (\\n00687| (\\n00688| state.current_permission.tool\\n00689| and state.current_permission.tool.callID == part.callID\\n00690| and state.current_permission.tool.messageID == part.messageID\\n00691| )\\n00692| ---@TODO this is for backward compatibility, remove later\\n00693| or (state.current_permission.messageID == part.messageID and state.current_permission.callID == part.callID)\\n00694| )\\n00695| then\\n00696| M._handle_permission_request(output, part)\\n00697| end\\n00698| \\n00699| local end_line = output:get_line_count()\\n00700| if end_line - start_line > 1 then\\n00701| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1)\\n00702| end\\n00703| end\\n00704| \\n00705| ---@param output Output Output object to write to\\n00706| ---@param input TaskToolInput data for the tool\\n00707| ---@param metadata TaskToolMetadata Metadata for the tool use\\n00708| ---@param tool_output string\\n00709| function M._format_task_tool(output, input, metadata, tool_output)\\n00710| local start_line = output:get_line_count() + 1\\n00711| M._format_action(output, icons.get('task') .. ' task', input and input.description)\\n00712| \\n00713| if config.ui.output.tools.show_output then\\n00714| if tool_output and tool_output ~= '' then\\n00715| output:add_empty_line()\\n00716| output:add_lines(vim.split(tool_output, '\\\\n'))\\n00717| output:add_empty_line()\\n00718| end\\n00719| \\n00720| if metadata.summary and type(metadata.summary) == 'table' then\\n00721| for _, sub_part in ipairs(metadata.summary) do\\n00722| if sub_part.type == 'tool' and sub_part.tool then\\n00723| M._format_tool(output, sub_part)\\n00724| end\\n00725| end\\n00726| end\\n00727| end\\n00728| \\n00729| local end_line = output:get_line_count()\\n00730| output:add_action({\\n00731| text = '[S]elect Child Session',\\n00732| type = 'select_child_session',\\n00733| args = {},\\n00734| key = 'S',\\n00735| display_line = start_line - 1,\\n00736| range = { from = start_line, to = end_line },\\n00737| })\\n00738| end\\n00739| \\n00740| ---@param output Output Output object to write to\\n00741| ---@param lines string[]\\n00742| ---@param language string\\n00743| function M._format_code(output, lines, language)\\n00744| output:add_empty_line()\\n00745| --- NOTE: use longer code fence because lines could contain ```\\n00746| output:add_line('`````' .. (language or ''))\\n00747| output:add_lines(util.sanitize_lines(lines))\\n00748| output:add_line('`````')\\n00749| end\\n00750| \\n00751| ---@param output Output Output object to write to\\n00752| ---@param code string\\n00753| ---@param file_type string\\n00754| function M._format_diff(output, code, file_type)\\n00755| output:add_empty_line()\\n00756| \\n00757| --- NOTE: use longer code fence because code could contain ```\\n00758| output:add_line('`````' .. file_type)\\n00759| local lines = vim.split(code, '\\\\n')\\n00760| if #lines > 5 then\\n00761| lines = vim.list_slice(lines, 6)\\n00762| end\\n00763| \\n00764| for _, line in ipairs(lines) do\\n00765| local first_char = line:sub(1, 1)\\n00766| if first_char == '+' or first_char == '-' then\\n00767| local hl_group = first_char == '+' and 'OpencodeDiffAdd' or 'OpencodeDiffDelete'\\n00768| output:add_line(' ' .. line:sub(2))\\n00769| local line_idx = output:get_line_count()\\n00770| output:add_extmark(line_idx - 1, function()\\n00771| return {\\n00772| end_col = 0,\\n00773| end_row = line_idx,\\n00774| virt_text = { { first_char, hl_group } },\\n00775| hl_group = hl_group,\\n00776| hl_eol = true,\\n00777| priority = 5000,\\n00778| right_gravity = true,\\n00779| end_right_gravity = false,\\n00780| virt_text_hide = false,\\n00781| virt_text_pos = 'overlay',\\n00782| virt_text_repeat_linebreak = false,\\n00783| }\\n00784| end)\\n00785| else\\n00786| output:add_line(line)\\n00787| end\\n00788| end\\n00789| output:add_line('`````')\\n00790| end\\n00791| \\n00792| ---@param output Output Output object to write to\\n00793| ---@param start_line number\\n00794| ---@param end_line number\\n00795| ---@param hl_group string Highlight group for the border character\\n00796| ---@param win_col number\\n00797| ---@param text_hl_group? string Optional highlight group for the background/foreground of text lines\\n00798| function M._add_vertical_border(output, start_line, end_line, hl_group, win_col, text_hl_group)\\n00799| for line = start_line, end_line do\\n00800| local extmark_opts = {\\n00801| virt_text = { { require('opencode.ui.icons').get('border'), hl_group } },\\n00802| virt_text_pos = 'overlay',\\n00803| virt_text_win_col = win_col,\\n00804| virt_text_repeat_linebreak = true,\\n00805| }\\n00806| \\n00807| -- Add line highlight if text_hl_group is provided\\n00808| if text_hl_group then\\n00809| extmark_opts.line_hl_group = text_hl_group\\n00810| end\\n00811| \\n00812| output:add_extmark(line - 1, extmark_opts --[[@as OutputExtmark]])\\n00813| end\\n00814| end\\n00815| \\n00816| ---Formats a single message part and returns the resulting output object\\n00817| ---@param part OpencodeMessagePart The part to format\\n00818| ---@param message? OpencodeMessage Optional message object to extract role and mentions from\\n00819| ---@param is_last_part? boolean Whether this is the last part in the message, used to show an error if there is one\\n00820| ---@return Output\\n00821| function M.format_part(part, message, is_last_part)\\n00822| local output = Output.new()\\n00823| \\n00824| if not message or not message.info or not message.info.role then\\n00825| return output\\n00826| end\\n00827| \\n00828| local content_added = false\\n00829| local role = message.info.role\\n00830| \\n00831| if role == 'user' then\\n00832| if part.type == 'text' and part.text then\\n00833| if part.synthetic == true then\\n00834| M._format_selection_context(output, part)\\n00835| M._format_cursor_data_context(output, part)\\n00836| M._format_diagnostics_context(output, part)\\n00837| else\\n00838| M._format_user_prompt(output, vim.trim(part.text), message)\\n00839| content_added = true\\n00840| end\\n00841| elseif part.type == 'file' then\\n00842| local file_line = M._format_context_file(output, part.filename)\\n00843| if file_line then\\n00844| M._add_vertical_border(output, file_line - 1, file_line, 'OpencodeMessageRoleUser', -3)\\n00845| content_added = true\\n00846| end\\n00847| end\\n00848| elseif role == 'assistant' then\\n00849| if part.type == 'text' and part.text then\\n00850| M._format_assistant_message(output, vim.trim(part.text))\\n00851| content_added = true\\n00852| elseif part.type == 'reasoning' and part.text then\\n00853| M._format_reasoning(output, part)\\n00854| content_added = true\\n00855| elseif part.type == 'tool' then\\n00856| M._format_tool(output, part)\\n00857| content_added = true\\n00858| elseif part.type == 'patch' and part.hash then\\n00859| M._format_patch(output, part)\\n00860| content_added = true\\n00861| end\\n00862| end\\n00863| \\n00864| if content_added then\\n00865| output:add_empty_line()\\n00866| end\\n00867| \\n00868| if is_last_part and role == 'assistant' and message.info.error and message.info.error ~= '' then\\n00869| local error = message.info.error\\n00870| local error_message = error.data and error.data.message or vim.inspect(error)\\n00871| M._format_callout(output, 'ERROR', error_message)\\n00872| output:add_empty_line()\\n00873| end\\n00874| \\n00875| return output\\n00876| end\\n00877| \\n00878| return M\\n00879| \\n\\n(End of file - total 879 lines)\\n\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"file\",\"url\":\"file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\",\"id\":\"prt_b8e7c60a7002ybV09VDHoQQeO7\",\"filename\":\"lua/opencode/ui/formatter.lua\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"mime\":\"text/plain\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3002XHHlk77vAPApvR\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"{\\\"content\\\":[{\\\"msg\\\":\\\"expected `SessionRevertInfo` but found `SessionRevertInfo?`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l156:c68\\\"},{\\\"msg\\\":\\\"expected `integer?` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l490:c43\\\"},{\\\"msg\\\":\\\"expected `integer` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l492:c45\\\"},{\\\"msg\\\":\\\"expected `integer?` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l492:c62\\\"},{\\\"msg\\\":\\\"state.active_session may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l156:c68\\\"},{\\\"msg\\\":\\\"state.messages[#state.messages] may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l272:c74\\\"},{\\\"msg\\\":\\\"state.messages may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l272:c74\\\"},{\\\"msg\\\":\\\"Undefined field `[diag.severity]`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l435:c42\\\"},{\\\"msg\\\":\\\"Undefined field `command`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l526:c34\\\"},{\\\"msg\\\":\\\"Undefined field `command`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l527:c47\\\"},{\\\"msg\\\":\\\"Cannot assign `number` to `integer`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l493:c5\\\"}],\\\"context_type\\\":\\\"diagnostics\\\"}\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"time\":{\"updated\":1767622074603,\"created\":1767622072149}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"providerID\":\"github-copilot\",\"role\":\"assistant\",\"path\":{\"root\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"cwd\":\"/home/francis/Projects/_nvim/opencode.nvim\"},\"agent\":\"build\",\"time\":{\"created\":1767622074609},\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"mode\":\"build\",\"modelID\":\"gpt-4.1\",\"id\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"parentID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"cost\":0,\"tokens\":{\"output\":0,\"reasoning\":0,\"input\":0,\"cache\":{\"write\":0,\"read\":0}}}},\"type\":\"message.updated\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"created\":1767622074530},\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"summary\":{\"diffs\":[]}}},\"type\":\"message.updated\"},{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"updated\":1767622074670,\"created\":1767622072149},\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"summary\":{\"deletions\":0,\"additions\":0,\"files\":0}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"step-start\",\"id\":\"prt_b8e7c6672001F10WAiQKbzNEtE\",\"snapshot\":\"5ba6e95774829e7f501299039b72b72dc32c6620\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"tool\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"id\":\"prt_b8e7c6686001cCV44vsFtbpF42\",\"state\":{\"status\":\"pending\",\"input\":{},\"raw\":\"\"},\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\",\"tool\":\"bash\"}},\"type\":\"message.part.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"tool\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"id\":\"prt_b8e7c6686001cCV44vsFtbpF42\",\"state\":{\"status\":\"running\",\"input\":{\"description\":\"Shows working tree status\",\"command\":\"git status\"},\"time\":{\"start\":1767622076189}},\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\",\"tool\":\"bash\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"tool\":{\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\"},\"patterns\":[\"git status\"],\"id\":\"per_b8e7c6744001DX6EZ9KHM15RLi\",\"permission\":\"bash\",\"always\":[\"git status*\"],\"metadata\":{}},\"type\":\"permission.asked\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"created\":1767622074530},\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"summary\":{\"title\":\"Running git status to list changed files\",\"diffs\":[]}}},\"type\":\"message.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"title\":\"Running git status for formatter.lua changes\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"updated\":1767622082619,\"created\":1767622072149},\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"summary\":{\"deletions\":0,\"additions\":0,\"files\":0}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"}]\n","before":"","deletions":0,"additions":1}]}}},"type":"message.updated"},{"properties":{"info":{"title":"Running git status for formatter.lua changes","version":"1.1.2","directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_47183a8abffeZzOLeJ3j2KV8f8","time":{"updated":1767622106805,"created":1767622072149},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","summary":{"deletions":0,"additions":1,"files":1}}},"type":"session.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"step-start","id":"prt_b8e7ce0ca001Hb5Sp11isapDGi","snapshot":"34a4eef77f714f2e3a282c410dbda315c4781fee","messageID":"msg_b8e7cde9e0013hRkUyt0X2yMil"}},"type":"message.part.updated"},{"properties":{"delta":" the","part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","messageID":"msg_b8e7cde9e0013hRkUyt0X2yMil","id":"prt_b8e7ce0cc001nZUgxwsgHwogal","text":"Here are the","time":{"start":1767622107340}}},"type":"message.part.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"delta":" according","part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","messageID":"msg_b8e7cde9e0013hRkUyt0X2yMil","id":"prt_b8e7ce0cc001nZUgxwsgHwogal","text":"Here are the files that have been changed according","time":{"start":1767622107340}}},"type":"message.part.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"delta":" staged","part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","messageID":"msg_b8e7cde9e0013hRkUyt0X2yMil","id":"prt_b8e7ce0cc001nZUgxwsgHwogal","text":"Here are the files that have been changed according to git status:\n\n- Modified (but not staged","time":{"start":1767622107340}}},"type":"message.part.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"delta":".lua","part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","messageID":"msg_b8e7cde9e0013hRkUyt0X2yMil","id":"prt_b8e7ce0cc001nZUgxwsgHwogal","text":"Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua","time":{"start":1767622107340}}},"type":"message.part.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"delta":"formatter","part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","messageID":"msg_b8e7cde9e0013hRkUyt0X2yMil","id":"prt_b8e7ce0cc001nZUgxwsgHwogal","text":"Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter","time":{"start":1767622107340}}},"type":"message.part.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"delta":"/","part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","messageID":"msg_b8e7cde9e0013hRkUyt0X2yMil","id":"prt_b8e7ce0cc001nZUgxwsgHwogal","text":"Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter.lua`\n - `lua/opencode/ui/","time":{"start":1767622107340}}},"type":"message.part.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"delta":" -","part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","messageID":"msg_b8e7cde9e0013hRkUyt0X2yMil","id":"prt_b8e7ce0cc001nZUgxwsgHwogal","text":"Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter.lua`\n - `lua/opencode/ui/renderer.lua`\n\n- Untracked files:\n -","time":{"start":1767622107340}}},"type":"message.part.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"delta":"/","part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","messageID":"msg_b8e7cde9e0013hRkUyt0X2yMil","id":"prt_b8e7ce0cc001nZUgxwsgHwogal","text":"Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter.lua`\n - `lua/opencode/ui/renderer.lua`\n\n- Untracked files:\n - `test.lua`\n - `tests/data/","time":{"start":1767622107340}}},"type":"message.part.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"delta":" currently","part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","messageID":"msg_b8e7cde9e0013hRkUyt0X2yMil","id":"prt_b8e7ce0cc001nZUgxwsgHwogal","text":"Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter.lua`\n - `lua/opencode/ui/renderer.lua`\n\n- Untracked files:\n - `test.lua`\n - `tests/data/permission_ask_new.json`\n\nNo files are currently","time":{"start":1767622107340}}},"type":"message.part.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"delta":" want","part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","messageID":"msg_b8e7cde9e0013hRkUyt0X2yMil","id":"prt_b8e7ce0cc001nZUgxwsgHwogal","text":"Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter.lua`\n - `lua/opencode/ui/renderer.lua`\n\n- Untracked files:\n - `test.lua`\n - `tests/data/permission_ask_new.json`\n\nNo files are currently staged for commit. Let me know if you want","time":{"start":1767622107340}}},"type":"message.part.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"delta":" stage","part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","messageID":"msg_b8e7cde9e0013hRkUyt0X2yMil","id":"prt_b8e7ce0cc001nZUgxwsgHwogal","text":"Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter.lua`\n - `lua/opencode/ui/renderer.lua`\n\n- Untracked files:\n - `test.lua`\n - `tests/data/permission_ask_new.json`\n\nNo files are currently staged for commit. Let me know if you want more details (like the diff), want to stage","time":{"start":1767622107340}}},"type":"message.part.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"delta":"!","part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","messageID":"msg_b8e7cde9e0013hRkUyt0X2yMil","id":"prt_b8e7ce0cc001nZUgxwsgHwogal","text":"Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter.lua`\n - `lua/opencode/ui/renderer.lua`\n\n- Untracked files:\n - `test.lua`\n - `tests/data/permission_ask_new.json`\n\nNo files are currently staged for commit. Let me know if you want more details (like the diff), want to stage/commit, or need help with anything else!","time":{"start":1767622107340}}},"type":"message.part.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","messageID":"msg_b8e7cde9e0013hRkUyt0X2yMil","id":"prt_b8e7ce0cc001nZUgxwsgHwogal","text":"Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter.lua`\n - `lua/opencode/ui/renderer.lua`\n\n- Untracked files:\n - `test.lua`\n - `tests/data/permission_ask_new.json`\n\nNo files are currently staged for commit. Let me know if you want more details (like the diff), want to stage/commit, or need help with anything else!","time":{"start":1767622108550,"end":1767622108550}}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"step-finish","messageID":"msg_b8e7cde9e0013hRkUyt0X2yMil","id":"prt_b8e7ce5860011MSYAyLSbWKBop","reason":"stop","cost":0,"snapshot":"34a4eef77f714f2e3a282c410dbda315c4781fee","tokens":{"output":111,"reasoning":0,"input":179,"cache":{"write":0,"read":20864}}}},"type":"message.part.updated"},{"properties":{"info":{"providerID":"github-copilot","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"agent":"build","finish":"stop","time":{"created":1767622106782},"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","mode":"build","modelID":"gpt-4.1","id":"msg_b8e7cde9e0013hRkUyt0X2yMil","parentID":"msg_b8e7c60a2001Kisjwk2mVB4dye","cost":0,"tokens":{"output":111,"reasoning":0,"input":179,"cache":{"write":0,"read":20864}}}},"type":"message.updated"},{"properties":{"info":{"providerID":"github-copilot","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"agent":"build","finish":"stop","time":{"created":1767622106782,"completed":1767622108574},"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","mode":"build","modelID":"gpt-4.1","id":"msg_b8e7cde9e0013hRkUyt0X2yMil","parentID":"msg_b8e7c60a2001Kisjwk2mVB4dye","cost":0,"tokens":{"output":111,"reasoning":0,"input":179,"cache":{"write":0,"read":20864}}}},"type":"message.updated"},{"properties":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8"},"type":"session.idle"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"info":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","time":{"created":1767622074530},"model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"role":"user","id":"msg_b8e7c60a2001Kisjwk2mVB4dye","agent":"build","system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","summary":{"title":"Running git status to list changed files","diffs":[{"file":"tests/data/permission_ask_new.json","after":"[{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"time\":{\"updated\":1767622072149,\"created\":1767622072149}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"time\":{\"created\":1767622074530}}},\"type\":\"message.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3001M2zsH9REfPdlQt\",\"text\":\"@no-trust run a git status and tell me what files are changed\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3003Ta9NcXkN0lb0lF\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"Called the Read tool with the following input: {\\\"filePath\\\":\\\"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\\\"}\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a7001d3WhKOu2vCR4Cf\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"\\n00001| local context_module = require('opencode.context')\\n00002| local icons = require('opencode.ui.icons')\\n00003| local util = require('opencode.util')\\n00004| local Output = require('opencode.ui.output')\\n00005| local state = require('opencode.state')\\n00006| local config = require('opencode.config')\\n00007| local snapshot = require('opencode.snapshot')\\n00008| local mention = require('opencode.ui.mention')\\n00009| \\n00010| local M = {}\\n00011| \\n00012| M.separator = {\\n00013| '----',\\n00014| '',\\n00015| }\\n00016| \\n00017| ---@param output Output\\n00018| ---@param part OpencodeMessagePart\\n00019| function M._format_reasoning(output, part)\\n00020| local text = vim.trim(part.text or '')\\n00021| if text == '' then\\n00022| return\\n00023| end\\n00024| \\n00025| local start_line = output:get_line_count() + 1\\n00026| \\n00027| local title = 'Reasoning'\\n00028| local time = part.time\\n00029| if time and type(time) == 'table' and time.start then\\n00030| local start_text = util.format_time(time.start) or ''\\n00031| local end_text = (time['end'] and util.format_time(time['end'])) or nil\\n00032| if end_text and end_text ~= '' then\\n00033| title = string.format('%s (%s - %s)', title, start_text, end_text)\\n00034| elseif start_text ~= '' then\\n00035| title = string.format('%s (%s)', title, start_text)\\n00036| end\\n00037| end\\n00038| \\n00039| M._format_action(output, icons.get('reasoning') .. ' ' .. title, '')\\n00040| \\n00041| if config.ui.output.tools.show_reasoning_output then\\n00042| output:add_empty_line()\\n00043| output:add_lines(vim.split(text, '\\\\n'))\\n00044| output:add_empty_line()\\n00045| end\\n00046| \\n00047| local end_line = output:get_line_count()\\n00048| if end_line - start_line > 1 then\\n00049| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1, 'OpencodeReasoningText')\\n00050| else\\n00051| output:add_extmark(start_line - 1, {\\n00052| line_hl_group = 'OpencodeReasoningText',\\n00053| } --[[@as OutputExtmark]])\\n00054| end\\n00055| end\\n00056| \\n00057| function M._handle_permission_request(output, part)\\n00058| if part.state and part.state.status == 'error' and part.state.error then\\n00059| if part.state.error:match('rejected permission') then\\n00060| state.current_permission = nil\\n00061| else\\n00062| vim.notify('Unknown part state error: ' .. part.state.error)\\n00063| end\\n00064| return\\n00065| end\\n00066| \\n00067| M._format_permission_request(output)\\n00068| end\\n00069| \\n00070| function M._format_permission_request(output)\\n00071| local keys\\n00072| \\n00073| if require('opencode.ui.ui').is_opencode_focused() then\\n00074| keys = {\\n00075| config.keymap.permission.accept,\\n00076| config.keymap.permission.accept_all,\\n00077| config.keymap.permission.deny,\\n00078| }\\n00079| else\\n00080| keys = {\\n00081| config.get_key_for_function('editor', 'permission_accept'),\\n00082| config.get_key_for_function('editor', 'permission_accept_all'),\\n00083| config.get_key_for_function('editor', 'permission_deny'),\\n00084| }\\n00085| end\\n00086| \\n00087| output:add_empty_line()\\n00088| output:add_line('> [!WARNING] Permission required to run this tool.')\\n00089| output:add_line('>')\\n00090| output:add_line(('> Accept `%s` Always `%s` Deny `%s`'):format(unpack(keys)))\\n00091| output:add_empty_line()\\n00092| end\\n00093| \\n00094| ---Calculate statistics for reverted messages and tool calls\\n00095| ---@param messages {info: MessageInfo, parts: OpencodeMessagePart[]}[] All messages in the session\\n00096| ---@param revert_index number Index of the message where revert occurred\\n00097| ---@param revert_info SessionRevertInfo Revert information\\n00098| ---@return {messages: number, tool_calls: number, files: table}\\n00099| function M._calculate_revert_stats(messages, revert_index, revert_info)\\n00100| local stats = {\\n00101| messages = 0,\\n00102| tool_calls = 0,\\n00103| files = {}, -- { [filename] = { additions = n, deletions = m } }\\n00104| }\\n00105| \\n00106| for i = revert_index, #messages do\\n00107| local msg = messages[i]\\n00108| if msg.info.role == 'user' then\\n00109| stats.messages = stats.messages + 1\\n00110| end\\n00111| if msg.parts then\\n00112| for _, part in ipairs(msg.parts) do\\n00113| if part.type == 'tool' then\\n00114| stats.tool_calls = stats.tool_calls + 1\\n00115| end\\n00116| end\\n00117| end\\n00118| end\\n00119| \\n00120| if revert_info.diff then\\n00121| local current_file = nil\\n00122| for line in revert_info.diff:gmatch('[^\\\\r\\\\n]+') do\\n00123| local file_a = line:match('^%-%-%- ([ab]/.+)')\\n00124| local file_b = line:match('^%+%+%+ ([ab]/.+)')\\n00125| if file_b then\\n00126| current_file = file_b:gsub('^[ab]/', '')\\n00127| if not stats.files[current_file] then\\n00128| stats.files[current_file] = { additions = 0, deletions = 0 }\\n00129| end\\n00130| elseif file_a then\\n00131| current_file = file_a:gsub('^[ab]/', '')\\n00132| if not stats.files[current_file] then\\n00133| stats.files[current_file] = { additions = 0, deletions = 0 }\\n00134| end\\n00135| elseif line:sub(1, 1) == '+' and not line:match('^%+%+%+') then\\n00136| if current_file then\\n00137| stats.files[current_file].additions = stats.files[current_file].additions + 1\\n00138| end\\n00139| elseif line:sub(1, 1) == '-' and not line:match('^%-%-%-') then\\n00140| if current_file then\\n00141| stats.files[current_file].deletions = stats.files[current_file].deletions + 1\\n00142| end\\n00143| end\\n00144| end\\n00145| end\\n00146| \\n00147| return stats\\n00148| end\\n00149| \\n00150| ---Format the revert callout with statistics\\n00151| ---@param session_data OpencodeMessage[] All messages in the session\\n00152| ---@param start_idx number Index of the message where revert occurred\\n00153| ---@return Output output object representing the lines, extmarks, and actions\\n00154| function M._format_revert_message(session_data, start_idx)\\n00155| local output = Output.new()\\n00156| local stats = M._calculate_revert_stats(session_data, start_idx, state.active_session.revert)\\n00157| local message_text = stats.messages == 1 and 'message' or 'messages'\\n00158| local tool_text = stats.tool_calls == 1 and 'tool call' or 'tool calls'\\n00159| \\n00160| output:add_lines(M.separator)\\n00161| output:add_line(\\n00162| string.format('> %d %s reverted, %d %s reverted', stats.messages, message_text, stats.tool_calls, tool_text)\\n00163| )\\n00164| output:add_line('>')\\n00165| output:add_line('> type `/redo` to restore.')\\n00166| output:add_empty_line()\\n00167| \\n00168| if stats.files and next(stats.files) then\\n00169| for file, fstats in pairs(stats.files) do\\n00170| local file_diff = {}\\n00171| if fstats.additions > 0 then\\n00172| table.insert(file_diff, '+' .. fstats.additions)\\n00173| end\\n00174| if fstats.deletions > 0 then\\n00175| table.insert(file_diff, '-' .. fstats.deletions)\\n00176| end\\n00177| if #file_diff > 0 then\\n00178| local line_str = string.format(icons.get('file') .. '%s: %s', file, table.concat(file_diff, ' '))\\n00179| local line_idx = output:add_line(line_str)\\n00180| local col = #(' ' .. file .. ': ')\\n00181| for _, diff in ipairs(file_diff) do\\n00182| local hl_group = diff:sub(1, 1) == '+' and 'OpencodeDiffAddText' or 'OpencodeDiffDeleteText'\\n00183| output:add_extmark(line_idx - 1, {\\n00184| virt_text = { { diff, hl_group } },\\n00185| virt_text_pos = 'inline',\\n00186| virt_text_win_col = col,\\n00187| priority = 1000,\\n00188| } --[[@as OutputExtmark]])\\n00189| col = col + #diff + 1\\n00190| end\\n00191| end\\n00192| end\\n00193| end\\n00194| return output\\n00195| end\\n00196| \\n00197| local function add_action(output, text, action_type, args, key, line)\\n00198| -- actions use api-indexing (e.g. 0 indexed)\\n00199| line = (line or output:get_line_count()) - 1\\n00200| output:add_action({\\n00201| text = text,\\n00202| type = action_type,\\n00203| args = args,\\n00204| key = key,\\n00205| display_line = line,\\n00206| range = { from = line, to = line },\\n00207| })\\n00208| end\\n00209| \\n00210| ---@param output Output Output object to write to\\n00211| ---@param part OpencodeMessagePart\\n00212| function M._format_patch(output, part)\\n00213| if not part.hash then\\n00214| return\\n00215| end\\n00216| \\n00217| local restore_points = snapshot.get_restore_points_by_parent(part.hash) or {}\\n00218| M._format_action(output, icons.get('snapshot') .. ' Created Snapshot', vim.trim(part.hash:sub(1, 8)))\\n00219| \\n00220| -- Anchor all snapshot-level actions to the snapshot header line\\n00221| add_action(output, '[R]evert file', 'diff_revert_selected_file', { part.hash }, 'R')\\n00222| add_action(output, 'Revert [A]ll', 'diff_revert_all', { part.hash }, 'A')\\n00223| add_action(output, '[D]iff', 'diff_open', { part.hash }, 'D')\\n00224| \\n00225| if #restore_points > 0 then\\n00226| for _, restore_point in ipairs(restore_points) do\\n00227| output:add_line(\\n00228| string.format(\\n00229| ' %s Restore point `%s` - %s ',\\n00230| icons.get('restore_point'),\\n00231| vim.trim(restore_point.id:sub(1, 8)),\\n00232| util.format_time(restore_point.created_at)\\n00233| )\\n00234| )\\n00235| add_action(output, 'Restore [A]ll', 'diff_restore_snapshot_all', { restore_point.id }, 'A')\\n00236| add_action(output, '[R]estore file', 'diff_restore_snapshot_file', { restore_point.id }, 'R')\\n00237| end\\n00238| end\\n00239| end\\n00240| \\n00241| ---@param output Output Output object to write to\\n00242| ---@param message MessageInfo\\n00243| function M._format_error(output, message)\\n00244| output:add_empty_line()\\n00245| M._format_callout(output, 'ERROR', vim.inspect(message.error))\\n00246| end\\n00247| \\n00248| ---@param message OpencodeMessage\\n00249| ---@return Output\\n00250| function M.format_message_header(message)\\n00251| local output = Output.new()\\n00252| \\n00253| output:add_lines(M.separator)\\n00254| local role = message.info.role or 'unknown'\\n00255| local icon = message.info.role == 'user' and icons.get('header_user') or icons.get('header_assistant')\\n00256| \\n00257| local time = message.info.time and message.info.time.created or nil\\n00258| local time_text = (time and ' (' .. util.format_time(time) .. ')' or '')\\n00259| local role_hl = 'OpencodeMessageRole' .. role:sub(1, 1):upper() .. role:sub(2)\\n00260| local model_text = message.info.modelID and ' ' .. message.info.modelID or ''\\n00261| \\n00262| local debug_text = config.debug.show_ids and ' [' .. message.info.id .. ']' or ''\\n00263| \\n00264| local display_name\\n00265| if role == 'assistant' then\\n00266| local mode = message.info.mode\\n00267| if mode and mode ~= '' then\\n00268| display_name = mode:upper()\\n00269| else\\n00270| -- For the most recent assistant message, show current_mode if mode is missing\\n00271| -- This handles new messages that haven't been stamped yet\\n00272| local is_last_message = #state.messages == 0 or message.info.id == state.messages[#state.messages].info.id\\n00273| if is_last_message and state.current_mode and state.current_mode ~= '' then\\n00274| display_name = state.current_mode:upper()\\n00275| else\\n00276| display_name = 'ASSISTANT'\\n00277| end\\n00278| end\\n00279| else\\n00280| display_name = role:upper()\\n00281| end\\n00282| \\n00283| output:add_extmark(output:get_line_count() - 1, {\\n00284| virt_text = {\\n00285| { icon, role_hl },\\n00286| { ' ' },\\n00287| { display_name, role_hl },\\n00288| { model_text, 'OpencodeHint' },\\n00289| { time_text, 'OpencodeHint' },\\n00290| { debug_text, 'OpencodeHint' },\\n00291| },\\n00292| virt_text_win_col = -3,\\n00293| priority = 10,\\n00294| } --[[@as OutputExtmark]])\\n00295| \\n00296| -- Only want to show the error if we have no parts. If we have parts, they'll\\n00297| -- handle rendering the error\\n00298| if\\n00299| role == 'assistant'\\n00300| and message.info.error\\n00301| and message.info.error ~= ''\\n00302| and (not message.parts or #message.parts == 0)\\n00303| then\\n00304| local error = message.info.error\\n00305| local error_message = error.data and error.data.message or vim.inspect(error)\\n00306| \\n00307| output:add_line('')\\n00308| M._format_callout(output, 'ERROR', error_message)\\n00309| end\\n00310| \\n00311| output:add_line('')\\n00312| return output\\n00313| end\\n00314| \\n00315| ---@param output Output Output object to write to\\n00316| ---@param callout string Callout type (e.g., 'ERROR', 'TODO')\\n00317| ---@param text string Callout text content\\n00318| ---@param title? string Optional title for the callout\\n00319| function M._format_callout(output, callout, text, title)\\n00320| title = title and title .. ' ' or ''\\n00321| local win_width = (state.windows and state.windows.output_win and vim.api.nvim_win_is_valid(state.windows.output_win))\\n00322| and vim.api.nvim_win_get_width(state.windows.output_win)\\n00323| or config.ui.window_width\\n00324| or 80\\n00325| if #text > win_width - 4 then\\n00326| local ok, substituted = pcall(vim.fn.substitute, text, '\\\\v(.{' .. (win_width - 8) .. '})', '\\\\1\\\\n', 'g')\\n00327| text = ok and substituted or text\\n00328| end\\n00329| \\n00330| -- Trim off any trailing newlines so there isn't an extra line in the\\n00331| -- extmarks section\\n00332| local lines = vim.split(text:gsub('\\\\n$', ''), '\\\\n')\\n00333| if #lines == 1 and title == '' then\\n00334| output:add_line('> [!' .. callout .. '] ' .. lines[1])\\n00335| else\\n00336| output:add_line('> [!' .. callout .. ']' .. title)\\n00337| output:add_line('>')\\n00338| output:add_lines(lines, '> ')\\n00339| end\\n00340| end\\n00341| \\n00342| ---@param output Output Output object to write to\\n00343| ---@param text string\\n00344| ---@param message? OpencodeMessage Optional message object to extract mentions from\\n00345| function M._format_user_prompt(output, text, message)\\n00346| local start_line = output:get_line_count()\\n00347| \\n00348| output:add_lines(vim.split(text, '\\\\n'))\\n00349| \\n00350| local end_line = output:get_line_count()\\n00351| \\n00352| local end_line_extmark_offset = 0\\n00353| \\n00354| local mentions = {}\\n00355| if message and message.parts then\\n00356| -- message.parts will only be filled out on a re-render\\n00357| -- we need to collect the mentions here\\n00358| for _, part in ipairs(message.parts) do\\n00359| if part.type == 'file' then\\n00360| -- we're rerendering this part and we have files, the space after the user prompt\\n00361| -- also needs an extmark\\n00362| end_line_extmark_offset = 1\\n00363| if part.source and part.source.text then\\n00364| table.insert(mentions, part.source.text)\\n00365| end\\n00366| elseif part.type == 'agent' then\\n00367| if part.source then\\n00368| table.insert(mentions, part.source)\\n00369| end\\n00370| end\\n00371| end\\n00372| end\\n00373| \\n00374| if #mentions > 0 then\\n00375| mention.highlight_mentions_in_output(output, text, mentions, start_line)\\n00376| end\\n00377| \\n00378| M._add_vertical_border(output, start_line, end_line + end_line_extmark_offset, 'OpencodeMessageRoleUser', -3)\\n00379| end\\n00380| \\n00381| ---@param output Output Output object to write to\\n00382| ---@param part OpencodeMessagePart\\n00383| function M._format_selection_context(output, part)\\n00384| local json = context_module.decode_json_context(part.text or '', 'selection')\\n00385| if not json then\\n00386| return\\n00387| end\\n00388| local start_line = output:get_line_count()\\n00389| output:add_lines(vim.split(json.content or '', '\\\\n'))\\n00390| output:add_empty_line()\\n00391| \\n00392| local end_line = output:get_line_count()\\n00393| \\n00394| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00395| end\\n00396| \\n00397| ---@param output Output Output object to write to\\n00398| ---@param part OpencodeMessagePart\\n00399| function M._format_cursor_data_context(output, part)\\n00400| local json = context_module.decode_json_context(part.text or '', 'cursor-data')\\n00401| if not json then\\n00402| return\\n00403| end\\n00404| local start_line = output:get_line_count()\\n00405| output:add_line('Line ' .. json.line .. ':')\\n00406| output:add_lines(vim.split(json.line_content or '', '\\\\n'))\\n00407| output:add_empty_line()\\n00408| \\n00409| local end_line = output:get_line_count()\\n00410| \\n00411| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00412| end\\n00413| \\n00414| ---@param output Output Output object to write to\\n00415| ---@param part OpencodeMessagePart\\n00416| function M._format_diagnostics_context(output, part)\\n00417| local json = context_module.decode_json_context(part.text or '', 'diagnostics')\\n00418| if not json then\\n00419| return\\n00420| end\\n00421| local start_line = output:get_line_count()\\n00422| local diagnostics = json.content --[[@as OpencodeDiagnostic[] ]]\\n00423| if not diagnostics or type(diagnostics) ~= 'table' or #diagnostics == 0 then\\n00424| return\\n00425| end\\n00426| \\n00427| local diagnostics_count = { error = 0, warn = 0, info = 0 }\\n00428| local diagnostics_icons = {\\n00429| error = icons.get('error'),\\n00430| warn = icons.get('warning'),\\n00431| info = icons.get('info'),\\n00432| }\\n00433| \\n00434| for _, diag in ipairs(diagnostics) do\\n00435| local name = vim.diagnostic.severity[diag.severity]:lower()\\n00436| diagnostics_count[name] = diagnostics_count[name] + 1\\n00437| end\\n00438| \\n00439| local diag_line = '**Diagnostics:**'\\n00440| for name, count in pairs(diagnostics_count) do\\n00441| if count > 0 then\\n00442| diag_line = diag_line .. (string.format(' %s(%d)', diagnostics_icons[name], count))\\n00443| end\\n00444| end\\n00445| output:add_line(diag_line)\\n00446| output:add_empty_line()\\n00447| local end_line = output:get_line_count()\\n00448| \\n00449| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00450| end\\n00451| \\n00452| ---Format and display the file path in the context\\n00453| ---@param output Output Output object to write to\\n00454| ---@param path string|nil File path\\n00455| function M._format_context_file(output, path)\\n00456| if not path or path == '' then\\n00457| return\\n00458| end\\n00459| local cwd = vim.fn.getcwd()\\n00460| if vim.startswith(path, cwd) then\\n00461| path = path:sub(#cwd + 2)\\n00462| end\\n00463| return output:add_line(string.format('[%s](%s)', path, path))\\n00464| end\\n00465| \\n00466| ---@param output Output Output object to write to\\n00467| ---@param text string\\n00468| function M._format_assistant_message(output, text)\\n00469| local reference_picker = require('opencode.ui.reference_picker')\\n00470| local references = reference_picker.parse_references(text, '')\\n00471| \\n00472| -- If no references, just add the text as-is\\n00473| if #references == 0 then\\n00474| output:add_lines(vim.split(text, '\\\\n'))\\n00475| return\\n00476| end\\n00477| \\n00478| -- Sort references by match_start position (ascending)\\n00479| table.sort(references, function(a, b)\\n00480| return a.match_start < b.match_start\\n00481| end)\\n00482| \\n00483| -- Build a new text with icons inserted before each reference\\n00484| local result = ''\\n00485| local last_pos = 1\\n00486| local ref_icon = icons.get('reference')\\n00487| \\n00488| for _, ref in ipairs(references) do\\n00489| -- Add text before this reference\\n00490| result = result .. text:sub(last_pos, ref.match_start - 1)\\n00491| -- Add the icon and the reference\\n00492| result = result .. ref_icon .. text:sub(ref.match_start, ref.match_end)\\n00493| last_pos = ref.match_end + 1\\n00494| end\\n00495| \\n00496| -- Add any remaining text after the last reference\\n00497| if last_pos <= #text then\\n00498| result = result .. text:sub(last_pos)\\n00499| end\\n00500| \\n00501| output:add_lines(vim.split(result, '\\\\n'))\\n00502| end\\n00503| \\n00504| ---@param output Output Output object to write to\\n00505| ---@param tool_type string Tool type (e.g., 'run', 'read', 'edit', etc.)\\n00506| ---@param value string Value associated with the action (e.g., filename, command)\\n00507| function M._format_action(output, tool_type, value)\\n00508| if not tool_type or not value then\\n00509| return\\n00510| end\\n00511| local line = string.format('**%s** %s', tool_type, value and #value > 0 and ('`' .. value .. '`') or '')\\n00512| \\n00513| output:add_line(line)\\n00514| end\\n00515| \\n00516| ---@param output Output Output object to write to\\n00517| ---@param input BashToolInput data for the tool\\n00518| ---@param metadata BashToolMetadata Metadata for the tool use\\n00519| function M._format_bash_tool(output, input, metadata)\\n00520| M._format_action(output, icons.get('run') .. ' run', input and input.description)\\n00521| \\n00522| if not config.ui.output.tools.show_output then\\n00523| return\\n00524| end\\n00525| \\n00526| if metadata.output or metadata.command or input.command then\\n00527| local command = input.command or metadata.command or ''\\n00528| local command_output = metadata.output and metadata.output ~= '' and ('\\\\n' .. metadata.output) or ''\\n00529| M._format_code(output, vim.split('> ' .. command .. '\\\\n' .. command_output, '\\\\n'), 'bash')\\n00530| end\\n00531| end\\n00532| \\n00533| ---@param output Output Output object to write to\\n00534| ---@param tool_type string Tool type (e.g., 'read', 'edit', 'write')\\n00535| ---@param input FileToolInput data for the tool\\n00536| ---@param metadata FileToolMetadata Metadata for the tool use\\n00537| function M._format_file_tool(output, tool_type, input, metadata)\\n00538| local file_name = input and vim.fn.fnamemodify(input.filePath, ':t') or ''\\n00539| local file_type = input and util.get_markdown_filetype(input.filePath) or ''\\n00540| local tool_action_icons = { read = icons.get('read'), edit = icons.get('edit'), write = icons.get('write') }\\n00541| \\n00542| M._format_action(output, tool_action_icons[tool_type] .. ' ' .. tool_type, file_name)\\n00543| \\n00544| if not config.ui.output.tools.show_output then\\n00545| return\\n00546| end\\n00547| \\n00548| if tool_type == 'edit' and metadata.diff then\\n00549| M._format_diff(output, metadata.diff, file_type)\\n00550| elseif tool_type == 'write' and input and input.content then\\n00551| M._format_code(output, vim.split(input.content, '\\\\n'), file_type)\\n00552| end\\n00553| end\\n00554| \\n00555| ---@param output Output Output object to write to\\n00556| ---@param title string\\n00557| ---@param input TodoToolInput\\n00558| function M._format_todo_tool(output, title, input)\\n00559| M._format_action(output, icons.get('plan') .. ' plan', (title or ''))\\n00560| if not config.ui.output.tools.show_output then\\n00561| return\\n00562| end\\n00563| \\n00564| local todos = input and input.todos or {}\\n00565| \\n00566| for _, item in ipairs(todos) do\\n00567| local statuses = { in_progress = '-', completed = 'x', pending = ' ' }\\n00568| output:add_line(string.format('- [%s] %s ', statuses[item.status], item.content))\\n00569| end\\n00570| end\\n00571| \\n00572| ---@param output Output Output object to write to\\n00573| ---@param input GlobToolInput data for the tool\\n00574| ---@param metadata GlobToolMetadata Metadata for the tool use\\n00575| function M._format_glob_tool(output, input, metadata)\\n00576| M._format_action(output, icons.get('search') .. ' glob', input and input.pattern)\\n00577| if not config.ui.output.tools.show_output then\\n00578| return\\n00579| end\\n00580| local prefix = metadata.truncated and ' more than' or ''\\n00581| output:add_line(string.format('Found%s `%d` file(s):', prefix, metadata.count or 0))\\n00582| end\\n00583| \\n00584| ---@param output Output Output object to write to\\n00585| ---@param input GrepToolInput data for the tool\\n00586| ---@param metadata GrepToolMetadata Metadata for the tool use\\n00587| function M._format_grep_tool(output, input, metadata)\\n00588| input = input or { path = '', include = '', pattern = '' }\\n00589| \\n00590| local grep_str = string.format('%s` `%s', (input.path or input.include) or '', input.pattern or '')\\n00591| \\n00592| M._format_action(output, icons.get('search') .. ' grep', grep_str)\\n00593| if not config.ui.output.tools.show_output then\\n00594| return\\n00595| end\\n00596| local prefix = metadata.truncated and ' more than' or ''\\n00597| output:add_line(\\n00598| string.format('Found%s `%d` match' .. (metadata.matches ~= 1 and 'es' or ''), prefix, metadata.matches or 0)\\n00599| )\\n00600| end\\n00601| \\n00602| ---@param output Output Output object to write to\\n00603| ---@param input WebFetchToolInput data for the tool\\n00604| function M._format_webfetch_tool(output, input)\\n00605| M._format_action(output, icons.get('web') .. ' fetch', input and input.url)\\n00606| end\\n00607| \\n00608| ---@param output Output Output object to write to\\n00609| ---@param input ListToolInput\\n00610| ---@param metadata ListToolMetadata\\n00611| ---@param tool_output string\\n00612| function M._format_list_tool(output, input, metadata, tool_output)\\n00613| M._format_action(output, icons.get('list') .. ' list', input and input.path or '')\\n00614| if not config.ui.output.tools.show_output then\\n00615| return\\n00616| end\\n00617| local lines = vim.split(vim.trim(tool_output or ''), '\\\\n')\\n00618| if #lines < 1 or metadata.count == 0 then\\n00619| output:add_line('No files found.')\\n00620| return\\n00621| end\\n00622| if #lines > 1 then\\n00623| output:add_line('Files:')\\n00624| for i = 2, #lines do\\n00625| local file = vim.trim(lines[i])\\n00626| if file ~= '' then\\n00627| output:add_line(' • ' .. file)\\n00628| end\\n00629| end\\n00630| end\\n00631| if metadata.truncated then\\n00632| output:add_line(string.format('Results truncated, showing first %d files', metadata.count or '?'))\\n00633| end\\n00634| end\\n00635| \\n00636| ---@param output Output Output object to write to\\n00637| ---@param part OpencodeMessagePart\\n00638| function M._format_tool(output, part)\\n00639| local tool = part.tool\\n00640| if not tool or not part.state then\\n00641| return\\n00642| end\\n00643| \\n00644| local start_line = output:get_line_count() + 1\\n00645| local input = part.state.input or {}\\n00646| local metadata = part.state.metadata or {}\\n00647| local tool_output = part.state.output or ''\\n00648| \\n00649| if state.current_permission and state.current_permission.messageID == part.messageID then\\n00650| metadata = state.current_permission.metadata or metadata\\n00651| end\\n00652| \\n00653| if tool == 'bash' then\\n00654| M._format_bash_tool(output, input --[[@as BashToolInput]], metadata --[[@as BashToolMetadata]])\\n00655| elseif tool == 'read' or tool == 'edit' or tool == 'write' then\\n00656| M._format_file_tool(output, tool, input --[[@as FileToolInput]], metadata --[[@as FileToolMetadata]])\\n00657| elseif tool == 'todowrite' then\\n00658| M._format_todo_tool(output, part.state.title, input --[[@as TodoToolInput]])\\n00659| elseif tool == 'glob' then\\n00660| M._format_glob_tool(output, input --[[@as GlobToolInput]], metadata --[[@as GlobToolMetadata]])\\n00661| elseif tool == 'list' then\\n00662| M._format_list_tool(output, input --[[@as ListToolInput]], metadata --[[@as ListToolMetadata]], tool_output)\\n00663| elseif tool == 'grep' then\\n00664| M._format_grep_tool(output, input --[[@as GrepToolInput]], metadata --[[@as GrepToolMetadata]])\\n00665| elseif tool == 'webfetch' then\\n00666| M._format_webfetch_tool(output, input --[[@as WebFetchToolInput]])\\n00667| elseif tool == 'task' then\\n00668| M._format_task_tool(output, input --[[@as TaskToolInput]], metadata --[[@as TaskToolMetadata]], tool_output)\\n00669| else\\n00670| M._format_action(output, icons.get('tool') .. ' tool', tool)\\n00671| end\\n00672| \\n00673| if part.state.status == 'error' and part.state.error then\\n00674| output:add_line('')\\n00675| M._format_callout(output, 'ERROR', part.state.error)\\n00676| ---@diagnostic disable-next-line: undefined-field\\n00677| elseif part.state.input and part.state.input.error then\\n00678| output:add_line('')\\n00679| ---I'm not sure about the type with state.input.error\\n00680| ---@diagnostic disable-next-line: undefined-field\\n00681| M._format_callout(output, 'ERROR', part.state.input.error)\\n00682| end\\n00683| \\n00684| if\\n00685| state.current_permission\\n00686| and (\\n00687| (\\n00688| state.current_permission.tool\\n00689| and state.current_permission.tool.callID == part.callID\\n00690| and state.current_permission.tool.messageID == part.messageID\\n00691| )\\n00692| ---@TODO this is for backward compatibility, remove later\\n00693| or (state.current_permission.messageID == part.messageID and state.current_permission.callID == part.callID)\\n00694| )\\n00695| then\\n00696| M._handle_permission_request(output, part)\\n00697| end\\n00698| \\n00699| local end_line = output:get_line_count()\\n00700| if end_line - start_line > 1 then\\n00701| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1)\\n00702| end\\n00703| end\\n00704| \\n00705| ---@param output Output Output object to write to\\n00706| ---@param input TaskToolInput data for the tool\\n00707| ---@param metadata TaskToolMetadata Metadata for the tool use\\n00708| ---@param tool_output string\\n00709| function M._format_task_tool(output, input, metadata, tool_output)\\n00710| local start_line = output:get_line_count() + 1\\n00711| M._format_action(output, icons.get('task') .. ' task', input and input.description)\\n00712| \\n00713| if config.ui.output.tools.show_output then\\n00714| if tool_output and tool_output ~= '' then\\n00715| output:add_empty_line()\\n00716| output:add_lines(vim.split(tool_output, '\\\\n'))\\n00717| output:add_empty_line()\\n00718| end\\n00719| \\n00720| if metadata.summary and type(metadata.summary) == 'table' then\\n00721| for _, sub_part in ipairs(metadata.summary) do\\n00722| if sub_part.type == 'tool' and sub_part.tool then\\n00723| M._format_tool(output, sub_part)\\n00724| end\\n00725| end\\n00726| end\\n00727| end\\n00728| \\n00729| local end_line = output:get_line_count()\\n00730| output:add_action({\\n00731| text = '[S]elect Child Session',\\n00732| type = 'select_child_session',\\n00733| args = {},\\n00734| key = 'S',\\n00735| display_line = start_line - 1,\\n00736| range = { from = start_line, to = end_line },\\n00737| })\\n00738| end\\n00739| \\n00740| ---@param output Output Output object to write to\\n00741| ---@param lines string[]\\n00742| ---@param language string\\n00743| function M._format_code(output, lines, language)\\n00744| output:add_empty_line()\\n00745| --- NOTE: use longer code fence because lines could contain ```\\n00746| output:add_line('`````' .. (language or ''))\\n00747| output:add_lines(util.sanitize_lines(lines))\\n00748| output:add_line('`````')\\n00749| end\\n00750| \\n00751| ---@param output Output Output object to write to\\n00752| ---@param code string\\n00753| ---@param file_type string\\n00754| function M._format_diff(output, code, file_type)\\n00755| output:add_empty_line()\\n00756| \\n00757| --- NOTE: use longer code fence because code could contain ```\\n00758| output:add_line('`````' .. file_type)\\n00759| local lines = vim.split(code, '\\\\n')\\n00760| if #lines > 5 then\\n00761| lines = vim.list_slice(lines, 6)\\n00762| end\\n00763| \\n00764| for _, line in ipairs(lines) do\\n00765| local first_char = line:sub(1, 1)\\n00766| if first_char == '+' or first_char == '-' then\\n00767| local hl_group = first_char == '+' and 'OpencodeDiffAdd' or 'OpencodeDiffDelete'\\n00768| output:add_line(' ' .. line:sub(2))\\n00769| local line_idx = output:get_line_count()\\n00770| output:add_extmark(line_idx - 1, function()\\n00771| return {\\n00772| end_col = 0,\\n00773| end_row = line_idx,\\n00774| virt_text = { { first_char, hl_group } },\\n00775| hl_group = hl_group,\\n00776| hl_eol = true,\\n00777| priority = 5000,\\n00778| right_gravity = true,\\n00779| end_right_gravity = false,\\n00780| virt_text_hide = false,\\n00781| virt_text_pos = 'overlay',\\n00782| virt_text_repeat_linebreak = false,\\n00783| }\\n00784| end)\\n00785| else\\n00786| output:add_line(line)\\n00787| end\\n00788| end\\n00789| output:add_line('`````')\\n00790| end\\n00791| \\n00792| ---@param output Output Output object to write to\\n00793| ---@param start_line number\\n00794| ---@param end_line number\\n00795| ---@param hl_group string Highlight group for the border character\\n00796| ---@param win_col number\\n00797| ---@param text_hl_group? string Optional highlight group for the background/foreground of text lines\\n00798| function M._add_vertical_border(output, start_line, end_line, hl_group, win_col, text_hl_group)\\n00799| for line = start_line, end_line do\\n00800| local extmark_opts = {\\n00801| virt_text = { { require('opencode.ui.icons').get('border'), hl_group } },\\n00802| virt_text_pos = 'overlay',\\n00803| virt_text_win_col = win_col,\\n00804| virt_text_repeat_linebreak = true,\\n00805| }\\n00806| \\n00807| -- Add line highlight if text_hl_group is provided\\n00808| if text_hl_group then\\n00809| extmark_opts.line_hl_group = text_hl_group\\n00810| end\\n00811| \\n00812| output:add_extmark(line - 1, extmark_opts --[[@as OutputExtmark]])\\n00813| end\\n00814| end\\n00815| \\n00816| ---Formats a single message part and returns the resulting output object\\n00817| ---@param part OpencodeMessagePart The part to format\\n00818| ---@param message? OpencodeMessage Optional message object to extract role and mentions from\\n00819| ---@param is_last_part? boolean Whether this is the last part in the message, used to show an error if there is one\\n00820| ---@return Output\\n00821| function M.format_part(part, message, is_last_part)\\n00822| local output = Output.new()\\n00823| \\n00824| if not message or not message.info or not message.info.role then\\n00825| return output\\n00826| end\\n00827| \\n00828| local content_added = false\\n00829| local role = message.info.role\\n00830| \\n00831| if role == 'user' then\\n00832| if part.type == 'text' and part.text then\\n00833| if part.synthetic == true then\\n00834| M._format_selection_context(output, part)\\n00835| M._format_cursor_data_context(output, part)\\n00836| M._format_diagnostics_context(output, part)\\n00837| else\\n00838| M._format_user_prompt(output, vim.trim(part.text), message)\\n00839| content_added = true\\n00840| end\\n00841| elseif part.type == 'file' then\\n00842| local file_line = M._format_context_file(output, part.filename)\\n00843| if file_line then\\n00844| M._add_vertical_border(output, file_line - 1, file_line, 'OpencodeMessageRoleUser', -3)\\n00845| content_added = true\\n00846| end\\n00847| end\\n00848| elseif role == 'assistant' then\\n00849| if part.type == 'text' and part.text then\\n00850| M._format_assistant_message(output, vim.trim(part.text))\\n00851| content_added = true\\n00852| elseif part.type == 'reasoning' and part.text then\\n00853| M._format_reasoning(output, part)\\n00854| content_added = true\\n00855| elseif part.type == 'tool' then\\n00856| M._format_tool(output, part)\\n00857| content_added = true\\n00858| elseif part.type == 'patch' and part.hash then\\n00859| M._format_patch(output, part)\\n00860| content_added = true\\n00861| end\\n00862| end\\n00863| \\n00864| if content_added then\\n00865| output:add_empty_line()\\n00866| end\\n00867| \\n00868| if is_last_part and role == 'assistant' and message.info.error and message.info.error ~= '' then\\n00869| local error = message.info.error\\n00870| local error_message = error.data and error.data.message or vim.inspect(error)\\n00871| M._format_callout(output, 'ERROR', error_message)\\n00872| output:add_empty_line()\\n00873| end\\n00874| \\n00875| return output\\n00876| end\\n00877| \\n00878| return M\\n00879| \\n\\n(End of file - total 879 lines)\\n\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"file\",\"url\":\"file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\",\"id\":\"prt_b8e7c60a7002ybV09VDHoQQeO7\",\"filename\":\"lua/opencode/ui/formatter.lua\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"mime\":\"text/plain\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3002XHHlk77vAPApvR\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"{\\\"content\\\":[{\\\"msg\\\":\\\"expected `SessionRevertInfo` but found `SessionRevertInfo?`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l156:c68\\\"},{\\\"msg\\\":\\\"expected `integer?` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l490:c43\\\"},{\\\"msg\\\":\\\"expected `integer` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l492:c45\\\"},{\\\"msg\\\":\\\"expected `integer?` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l492:c62\\\"},{\\\"msg\\\":\\\"state.active_session may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l156:c68\\\"},{\\\"msg\\\":\\\"state.messages[#state.messages] may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l272:c74\\\"},{\\\"msg\\\":\\\"state.messages may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l272:c74\\\"},{\\\"msg\\\":\\\"Undefined field `[diag.severity]`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l435:c42\\\"},{\\\"msg\\\":\\\"Undefined field `command`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l526:c34\\\"},{\\\"msg\\\":\\\"Undefined field `command`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l527:c47\\\"},{\\\"msg\\\":\\\"Cannot assign `number` to `integer`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l493:c5\\\"}],\\\"context_type\\\":\\\"diagnostics\\\"}\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"time\":{\"updated\":1767622074603,\"created\":1767622072149}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"providerID\":\"github-copilot\",\"role\":\"assistant\",\"path\":{\"root\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"cwd\":\"/home/francis/Projects/_nvim/opencode.nvim\"},\"agent\":\"build\",\"time\":{\"created\":1767622074609},\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"mode\":\"build\",\"modelID\":\"gpt-4.1\",\"id\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"parentID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"cost\":0,\"tokens\":{\"output\":0,\"reasoning\":0,\"input\":0,\"cache\":{\"write\":0,\"read\":0}}}},\"type\":\"message.updated\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"created\":1767622074530},\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"summary\":{\"diffs\":[]}}},\"type\":\"message.updated\"},{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"updated\":1767622074670,\"created\":1767622072149},\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"summary\":{\"deletions\":0,\"additions\":0,\"files\":0}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"step-start\",\"id\":\"prt_b8e7c6672001F10WAiQKbzNEtE\",\"snapshot\":\"5ba6e95774829e7f501299039b72b72dc32c6620\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"tool\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"id\":\"prt_b8e7c6686001cCV44vsFtbpF42\",\"state\":{\"status\":\"pending\",\"input\":{},\"raw\":\"\"},\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\",\"tool\":\"bash\"}},\"type\":\"message.part.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"tool\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"id\":\"prt_b8e7c6686001cCV44vsFtbpF42\",\"state\":{\"status\":\"running\",\"input\":{\"description\":\"Shows working tree status\",\"command\":\"git status\"},\"time\":{\"start\":1767622076189}},\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\",\"tool\":\"bash\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"tool\":{\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\"},\"patterns\":[\"git status\"],\"id\":\"per_b8e7c6744001DX6EZ9KHM15RLi\",\"permission\":\"bash\",\"always\":[\"git status*\"],\"metadata\":{}},\"type\":\"permission.asked\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"created\":1767622074530},\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"summary\":{\"title\":\"Running git status to list changed files\",\"diffs\":[]}}},\"type\":\"message.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"title\":\"Running git status for formatter.lua changes\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"updated\":1767622082619,\"created\":1767622072149},\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"summary\":{\"deletions\":0,\"additions\":0,\"files\":0}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"}]\n","before":"","deletions":0,"additions":1}]}}},"type":"message.updated"},{"properties":{"info":{"title":"Running git status for formatter.lua changes","version":"1.1.2","directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_47183a8abffeZzOLeJ3j2KV8f8","time":{"updated":1767622108600,"created":1767622072149},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","summary":{"deletions":0,"additions":1,"files":1}}},"type":"session.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"info":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","time":{"created":1767622074530},"model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"role":"user","id":"msg_b8e7c60a2001Kisjwk2mVB4dye","agent":"build","system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","summary":{"title":"Running git status to list changed files","diffs":[{"file":"tests/data/permission_ask_new.json","after":"[{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"time\":{\"updated\":1767622072149,\"created\":1767622072149}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"time\":{\"created\":1767622074530}}},\"type\":\"message.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3001M2zsH9REfPdlQt\",\"text\":\"@no-trust run a git status and tell me what files are changed\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3003Ta9NcXkN0lb0lF\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"Called the Read tool with the following input: {\\\"filePath\\\":\\\"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\\\"}\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a7001d3WhKOu2vCR4Cf\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"\\n00001| local context_module = require('opencode.context')\\n00002| local icons = require('opencode.ui.icons')\\n00003| local util = require('opencode.util')\\n00004| local Output = require('opencode.ui.output')\\n00005| local state = require('opencode.state')\\n00006| local config = require('opencode.config')\\n00007| local snapshot = require('opencode.snapshot')\\n00008| local mention = require('opencode.ui.mention')\\n00009| \\n00010| local M = {}\\n00011| \\n00012| M.separator = {\\n00013| '----',\\n00014| '',\\n00015| }\\n00016| \\n00017| ---@param output Output\\n00018| ---@param part OpencodeMessagePart\\n00019| function M._format_reasoning(output, part)\\n00020| local text = vim.trim(part.text or '')\\n00021| if text == '' then\\n00022| return\\n00023| end\\n00024| \\n00025| local start_line = output:get_line_count() + 1\\n00026| \\n00027| local title = 'Reasoning'\\n00028| local time = part.time\\n00029| if time and type(time) == 'table' and time.start then\\n00030| local start_text = util.format_time(time.start) or ''\\n00031| local end_text = (time['end'] and util.format_time(time['end'])) or nil\\n00032| if end_text and end_text ~= '' then\\n00033| title = string.format('%s (%s - %s)', title, start_text, end_text)\\n00034| elseif start_text ~= '' then\\n00035| title = string.format('%s (%s)', title, start_text)\\n00036| end\\n00037| end\\n00038| \\n00039| M._format_action(output, icons.get('reasoning') .. ' ' .. title, '')\\n00040| \\n00041| if config.ui.output.tools.show_reasoning_output then\\n00042| output:add_empty_line()\\n00043| output:add_lines(vim.split(text, '\\\\n'))\\n00044| output:add_empty_line()\\n00045| end\\n00046| \\n00047| local end_line = output:get_line_count()\\n00048| if end_line - start_line > 1 then\\n00049| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1, 'OpencodeReasoningText')\\n00050| else\\n00051| output:add_extmark(start_line - 1, {\\n00052| line_hl_group = 'OpencodeReasoningText',\\n00053| } --[[@as OutputExtmark]])\\n00054| end\\n00055| end\\n00056| \\n00057| function M._handle_permission_request(output, part)\\n00058| if part.state and part.state.status == 'error' and part.state.error then\\n00059| if part.state.error:match('rejected permission') then\\n00060| state.current_permission = nil\\n00061| else\\n00062| vim.notify('Unknown part state error: ' .. part.state.error)\\n00063| end\\n00064| return\\n00065| end\\n00066| \\n00067| M._format_permission_request(output)\\n00068| end\\n00069| \\n00070| function M._format_permission_request(output)\\n00071| local keys\\n00072| \\n00073| if require('opencode.ui.ui').is_opencode_focused() then\\n00074| keys = {\\n00075| config.keymap.permission.accept,\\n00076| config.keymap.permission.accept_all,\\n00077| config.keymap.permission.deny,\\n00078| }\\n00079| else\\n00080| keys = {\\n00081| config.get_key_for_function('editor', 'permission_accept'),\\n00082| config.get_key_for_function('editor', 'permission_accept_all'),\\n00083| config.get_key_for_function('editor', 'permission_deny'),\\n00084| }\\n00085| end\\n00086| \\n00087| output:add_empty_line()\\n00088| output:add_line('> [!WARNING] Permission required to run this tool.')\\n00089| output:add_line('>')\\n00090| output:add_line(('> Accept `%s` Always `%s` Deny `%s`'):format(unpack(keys)))\\n00091| output:add_empty_line()\\n00092| end\\n00093| \\n00094| ---Calculate statistics for reverted messages and tool calls\\n00095| ---@param messages {info: MessageInfo, parts: OpencodeMessagePart[]}[] All messages in the session\\n00096| ---@param revert_index number Index of the message where revert occurred\\n00097| ---@param revert_info SessionRevertInfo Revert information\\n00098| ---@return {messages: number, tool_calls: number, files: table}\\n00099| function M._calculate_revert_stats(messages, revert_index, revert_info)\\n00100| local stats = {\\n00101| messages = 0,\\n00102| tool_calls = 0,\\n00103| files = {}, -- { [filename] = { additions = n, deletions = m } }\\n00104| }\\n00105| \\n00106| for i = revert_index, #messages do\\n00107| local msg = messages[i]\\n00108| if msg.info.role == 'user' then\\n00109| stats.messages = stats.messages + 1\\n00110| end\\n00111| if msg.parts then\\n00112| for _, part in ipairs(msg.parts) do\\n00113| if part.type == 'tool' then\\n00114| stats.tool_calls = stats.tool_calls + 1\\n00115| end\\n00116| end\\n00117| end\\n00118| end\\n00119| \\n00120| if revert_info.diff then\\n00121| local current_file = nil\\n00122| for line in revert_info.diff:gmatch('[^\\\\r\\\\n]+') do\\n00123| local file_a = line:match('^%-%-%- ([ab]/.+)')\\n00124| local file_b = line:match('^%+%+%+ ([ab]/.+)')\\n00125| if file_b then\\n00126| current_file = file_b:gsub('^[ab]/', '')\\n00127| if not stats.files[current_file] then\\n00128| stats.files[current_file] = { additions = 0, deletions = 0 }\\n00129| end\\n00130| elseif file_a then\\n00131| current_file = file_a:gsub('^[ab]/', '')\\n00132| if not stats.files[current_file] then\\n00133| stats.files[current_file] = { additions = 0, deletions = 0 }\\n00134| end\\n00135| elseif line:sub(1, 1) == '+' and not line:match('^%+%+%+') then\\n00136| if current_file then\\n00137| stats.files[current_file].additions = stats.files[current_file].additions + 1\\n00138| end\\n00139| elseif line:sub(1, 1) == '-' and not line:match('^%-%-%-') then\\n00140| if current_file then\\n00141| stats.files[current_file].deletions = stats.files[current_file].deletions + 1\\n00142| end\\n00143| end\\n00144| end\\n00145| end\\n00146| \\n00147| return stats\\n00148| end\\n00149| \\n00150| ---Format the revert callout with statistics\\n00151| ---@param session_data OpencodeMessage[] All messages in the session\\n00152| ---@param start_idx number Index of the message where revert occurred\\n00153| ---@return Output output object representing the lines, extmarks, and actions\\n00154| function M._format_revert_message(session_data, start_idx)\\n00155| local output = Output.new()\\n00156| local stats = M._calculate_revert_stats(session_data, start_idx, state.active_session.revert)\\n00157| local message_text = stats.messages == 1 and 'message' or 'messages'\\n00158| local tool_text = stats.tool_calls == 1 and 'tool call' or 'tool calls'\\n00159| \\n00160| output:add_lines(M.separator)\\n00161| output:add_line(\\n00162| string.format('> %d %s reverted, %d %s reverted', stats.messages, message_text, stats.tool_calls, tool_text)\\n00163| )\\n00164| output:add_line('>')\\n00165| output:add_line('> type `/redo` to restore.')\\n00166| output:add_empty_line()\\n00167| \\n00168| if stats.files and next(stats.files) then\\n00169| for file, fstats in pairs(stats.files) do\\n00170| local file_diff = {}\\n00171| if fstats.additions > 0 then\\n00172| table.insert(file_diff, '+' .. fstats.additions)\\n00173| end\\n00174| if fstats.deletions > 0 then\\n00175| table.insert(file_diff, '-' .. fstats.deletions)\\n00176| end\\n00177| if #file_diff > 0 then\\n00178| local line_str = string.format(icons.get('file') .. '%s: %s', file, table.concat(file_diff, ' '))\\n00179| local line_idx = output:add_line(line_str)\\n00180| local col = #(' ' .. file .. ': ')\\n00181| for _, diff in ipairs(file_diff) do\\n00182| local hl_group = diff:sub(1, 1) == '+' and 'OpencodeDiffAddText' or 'OpencodeDiffDeleteText'\\n00183| output:add_extmark(line_idx - 1, {\\n00184| virt_text = { { diff, hl_group } },\\n00185| virt_text_pos = 'inline',\\n00186| virt_text_win_col = col,\\n00187| priority = 1000,\\n00188| } --[[@as OutputExtmark]])\\n00189| col = col + #diff + 1\\n00190| end\\n00191| end\\n00192| end\\n00193| end\\n00194| return output\\n00195| end\\n00196| \\n00197| local function add_action(output, text, action_type, args, key, line)\\n00198| -- actions use api-indexing (e.g. 0 indexed)\\n00199| line = (line or output:get_line_count()) - 1\\n00200| output:add_action({\\n00201| text = text,\\n00202| type = action_type,\\n00203| args = args,\\n00204| key = key,\\n00205| display_line = line,\\n00206| range = { from = line, to = line },\\n00207| })\\n00208| end\\n00209| \\n00210| ---@param output Output Output object to write to\\n00211| ---@param part OpencodeMessagePart\\n00212| function M._format_patch(output, part)\\n00213| if not part.hash then\\n00214| return\\n00215| end\\n00216| \\n00217| local restore_points = snapshot.get_restore_points_by_parent(part.hash) or {}\\n00218| M._format_action(output, icons.get('snapshot') .. ' Created Snapshot', vim.trim(part.hash:sub(1, 8)))\\n00219| \\n00220| -- Anchor all snapshot-level actions to the snapshot header line\\n00221| add_action(output, '[R]evert file', 'diff_revert_selected_file', { part.hash }, 'R')\\n00222| add_action(output, 'Revert [A]ll', 'diff_revert_all', { part.hash }, 'A')\\n00223| add_action(output, '[D]iff', 'diff_open', { part.hash }, 'D')\\n00224| \\n00225| if #restore_points > 0 then\\n00226| for _, restore_point in ipairs(restore_points) do\\n00227| output:add_line(\\n00228| string.format(\\n00229| ' %s Restore point `%s` - %s ',\\n00230| icons.get('restore_point'),\\n00231| vim.trim(restore_point.id:sub(1, 8)),\\n00232| util.format_time(restore_point.created_at)\\n00233| )\\n00234| )\\n00235| add_action(output, 'Restore [A]ll', 'diff_restore_snapshot_all', { restore_point.id }, 'A')\\n00236| add_action(output, '[R]estore file', 'diff_restore_snapshot_file', { restore_point.id }, 'R')\\n00237| end\\n00238| end\\n00239| end\\n00240| \\n00241| ---@param output Output Output object to write to\\n00242| ---@param message MessageInfo\\n00243| function M._format_error(output, message)\\n00244| output:add_empty_line()\\n00245| M._format_callout(output, 'ERROR', vim.inspect(message.error))\\n00246| end\\n00247| \\n00248| ---@param message OpencodeMessage\\n00249| ---@return Output\\n00250| function M.format_message_header(message)\\n00251| local output = Output.new()\\n00252| \\n00253| output:add_lines(M.separator)\\n00254| local role = message.info.role or 'unknown'\\n00255| local icon = message.info.role == 'user' and icons.get('header_user') or icons.get('header_assistant')\\n00256| \\n00257| local time = message.info.time and message.info.time.created or nil\\n00258| local time_text = (time and ' (' .. util.format_time(time) .. ')' or '')\\n00259| local role_hl = 'OpencodeMessageRole' .. role:sub(1, 1):upper() .. role:sub(2)\\n00260| local model_text = message.info.modelID and ' ' .. message.info.modelID or ''\\n00261| \\n00262| local debug_text = config.debug.show_ids and ' [' .. message.info.id .. ']' or ''\\n00263| \\n00264| local display_name\\n00265| if role == 'assistant' then\\n00266| local mode = message.info.mode\\n00267| if mode and mode ~= '' then\\n00268| display_name = mode:upper()\\n00269| else\\n00270| -- For the most recent assistant message, show current_mode if mode is missing\\n00271| -- This handles new messages that haven't been stamped yet\\n00272| local is_last_message = #state.messages == 0 or message.info.id == state.messages[#state.messages].info.id\\n00273| if is_last_message and state.current_mode and state.current_mode ~= '' then\\n00274| display_name = state.current_mode:upper()\\n00275| else\\n00276| display_name = 'ASSISTANT'\\n00277| end\\n00278| end\\n00279| else\\n00280| display_name = role:upper()\\n00281| end\\n00282| \\n00283| output:add_extmark(output:get_line_count() - 1, {\\n00284| virt_text = {\\n00285| { icon, role_hl },\\n00286| { ' ' },\\n00287| { display_name, role_hl },\\n00288| { model_text, 'OpencodeHint' },\\n00289| { time_text, 'OpencodeHint' },\\n00290| { debug_text, 'OpencodeHint' },\\n00291| },\\n00292| virt_text_win_col = -3,\\n00293| priority = 10,\\n00294| } --[[@as OutputExtmark]])\\n00295| \\n00296| -- Only want to show the error if we have no parts. If we have parts, they'll\\n00297| -- handle rendering the error\\n00298| if\\n00299| role == 'assistant'\\n00300| and message.info.error\\n00301| and message.info.error ~= ''\\n00302| and (not message.parts or #message.parts == 0)\\n00303| then\\n00304| local error = message.info.error\\n00305| local error_message = error.data and error.data.message or vim.inspect(error)\\n00306| \\n00307| output:add_line('')\\n00308| M._format_callout(output, 'ERROR', error_message)\\n00309| end\\n00310| \\n00311| output:add_line('')\\n00312| return output\\n00313| end\\n00314| \\n00315| ---@param output Output Output object to write to\\n00316| ---@param callout string Callout type (e.g., 'ERROR', 'TODO')\\n00317| ---@param text string Callout text content\\n00318| ---@param title? string Optional title for the callout\\n00319| function M._format_callout(output, callout, text, title)\\n00320| title = title and title .. ' ' or ''\\n00321| local win_width = (state.windows and state.windows.output_win and vim.api.nvim_win_is_valid(state.windows.output_win))\\n00322| and vim.api.nvim_win_get_width(state.windows.output_win)\\n00323| or config.ui.window_width\\n00324| or 80\\n00325| if #text > win_width - 4 then\\n00326| local ok, substituted = pcall(vim.fn.substitute, text, '\\\\v(.{' .. (win_width - 8) .. '})', '\\\\1\\\\n', 'g')\\n00327| text = ok and substituted or text\\n00328| end\\n00329| \\n00330| -- Trim off any trailing newlines so there isn't an extra line in the\\n00331| -- extmarks section\\n00332| local lines = vim.split(text:gsub('\\\\n$', ''), '\\\\n')\\n00333| if #lines == 1 and title == '' then\\n00334| output:add_line('> [!' .. callout .. '] ' .. lines[1])\\n00335| else\\n00336| output:add_line('> [!' .. callout .. ']' .. title)\\n00337| output:add_line('>')\\n00338| output:add_lines(lines, '> ')\\n00339| end\\n00340| end\\n00341| \\n00342| ---@param output Output Output object to write to\\n00343| ---@param text string\\n00344| ---@param message? OpencodeMessage Optional message object to extract mentions from\\n00345| function M._format_user_prompt(output, text, message)\\n00346| local start_line = output:get_line_count()\\n00347| \\n00348| output:add_lines(vim.split(text, '\\\\n'))\\n00349| \\n00350| local end_line = output:get_line_count()\\n00351| \\n00352| local end_line_extmark_offset = 0\\n00353| \\n00354| local mentions = {}\\n00355| if message and message.parts then\\n00356| -- message.parts will only be filled out on a re-render\\n00357| -- we need to collect the mentions here\\n00358| for _, part in ipairs(message.parts) do\\n00359| if part.type == 'file' then\\n00360| -- we're rerendering this part and we have files, the space after the user prompt\\n00361| -- also needs an extmark\\n00362| end_line_extmark_offset = 1\\n00363| if part.source and part.source.text then\\n00364| table.insert(mentions, part.source.text)\\n00365| end\\n00366| elseif part.type == 'agent' then\\n00367| if part.source then\\n00368| table.insert(mentions, part.source)\\n00369| end\\n00370| end\\n00371| end\\n00372| end\\n00373| \\n00374| if #mentions > 0 then\\n00375| mention.highlight_mentions_in_output(output, text, mentions, start_line)\\n00376| end\\n00377| \\n00378| M._add_vertical_border(output, start_line, end_line + end_line_extmark_offset, 'OpencodeMessageRoleUser', -3)\\n00379| end\\n00380| \\n00381| ---@param output Output Output object to write to\\n00382| ---@param part OpencodeMessagePart\\n00383| function M._format_selection_context(output, part)\\n00384| local json = context_module.decode_json_context(part.text or '', 'selection')\\n00385| if not json then\\n00386| return\\n00387| end\\n00388| local start_line = output:get_line_count()\\n00389| output:add_lines(vim.split(json.content or '', '\\\\n'))\\n00390| output:add_empty_line()\\n00391| \\n00392| local end_line = output:get_line_count()\\n00393| \\n00394| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00395| end\\n00396| \\n00397| ---@param output Output Output object to write to\\n00398| ---@param part OpencodeMessagePart\\n00399| function M._format_cursor_data_context(output, part)\\n00400| local json = context_module.decode_json_context(part.text or '', 'cursor-data')\\n00401| if not json then\\n00402| return\\n00403| end\\n00404| local start_line = output:get_line_count()\\n00405| output:add_line('Line ' .. json.line .. ':')\\n00406| output:add_lines(vim.split(json.line_content or '', '\\\\n'))\\n00407| output:add_empty_line()\\n00408| \\n00409| local end_line = output:get_line_count()\\n00410| \\n00411| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00412| end\\n00413| \\n00414| ---@param output Output Output object to write to\\n00415| ---@param part OpencodeMessagePart\\n00416| function M._format_diagnostics_context(output, part)\\n00417| local json = context_module.decode_json_context(part.text or '', 'diagnostics')\\n00418| if not json then\\n00419| return\\n00420| end\\n00421| local start_line = output:get_line_count()\\n00422| local diagnostics = json.content --[[@as OpencodeDiagnostic[] ]]\\n00423| if not diagnostics or type(diagnostics) ~= 'table' or #diagnostics == 0 then\\n00424| return\\n00425| end\\n00426| \\n00427| local diagnostics_count = { error = 0, warn = 0, info = 0 }\\n00428| local diagnostics_icons = {\\n00429| error = icons.get('error'),\\n00430| warn = icons.get('warning'),\\n00431| info = icons.get('info'),\\n00432| }\\n00433| \\n00434| for _, diag in ipairs(diagnostics) do\\n00435| local name = vim.diagnostic.severity[diag.severity]:lower()\\n00436| diagnostics_count[name] = diagnostics_count[name] + 1\\n00437| end\\n00438| \\n00439| local diag_line = '**Diagnostics:**'\\n00440| for name, count in pairs(diagnostics_count) do\\n00441| if count > 0 then\\n00442| diag_line = diag_line .. (string.format(' %s(%d)', diagnostics_icons[name], count))\\n00443| end\\n00444| end\\n00445| output:add_line(diag_line)\\n00446| output:add_empty_line()\\n00447| local end_line = output:get_line_count()\\n00448| \\n00449| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00450| end\\n00451| \\n00452| ---Format and display the file path in the context\\n00453| ---@param output Output Output object to write to\\n00454| ---@param path string|nil File path\\n00455| function M._format_context_file(output, path)\\n00456| if not path or path == '' then\\n00457| return\\n00458| end\\n00459| local cwd = vim.fn.getcwd()\\n00460| if vim.startswith(path, cwd) then\\n00461| path = path:sub(#cwd + 2)\\n00462| end\\n00463| return output:add_line(string.format('[%s](%s)', path, path))\\n00464| end\\n00465| \\n00466| ---@param output Output Output object to write to\\n00467| ---@param text string\\n00468| function M._format_assistant_message(output, text)\\n00469| local reference_picker = require('opencode.ui.reference_picker')\\n00470| local references = reference_picker.parse_references(text, '')\\n00471| \\n00472| -- If no references, just add the text as-is\\n00473| if #references == 0 then\\n00474| output:add_lines(vim.split(text, '\\\\n'))\\n00475| return\\n00476| end\\n00477| \\n00478| -- Sort references by match_start position (ascending)\\n00479| table.sort(references, function(a, b)\\n00480| return a.match_start < b.match_start\\n00481| end)\\n00482| \\n00483| -- Build a new text with icons inserted before each reference\\n00484| local result = ''\\n00485| local last_pos = 1\\n00486| local ref_icon = icons.get('reference')\\n00487| \\n00488| for _, ref in ipairs(references) do\\n00489| -- Add text before this reference\\n00490| result = result .. text:sub(last_pos, ref.match_start - 1)\\n00491| -- Add the icon and the reference\\n00492| result = result .. ref_icon .. text:sub(ref.match_start, ref.match_end)\\n00493| last_pos = ref.match_end + 1\\n00494| end\\n00495| \\n00496| -- Add any remaining text after the last reference\\n00497| if last_pos <= #text then\\n00498| result = result .. text:sub(last_pos)\\n00499| end\\n00500| \\n00501| output:add_lines(vim.split(result, '\\\\n'))\\n00502| end\\n00503| \\n00504| ---@param output Output Output object to write to\\n00505| ---@param tool_type string Tool type (e.g., 'run', 'read', 'edit', etc.)\\n00506| ---@param value string Value associated with the action (e.g., filename, command)\\n00507| function M._format_action(output, tool_type, value)\\n00508| if not tool_type or not value then\\n00509| return\\n00510| end\\n00511| local line = string.format('**%s** %s', tool_type, value and #value > 0 and ('`' .. value .. '`') or '')\\n00512| \\n00513| output:add_line(line)\\n00514| end\\n00515| \\n00516| ---@param output Output Output object to write to\\n00517| ---@param input BashToolInput data for the tool\\n00518| ---@param metadata BashToolMetadata Metadata for the tool use\\n00519| function M._format_bash_tool(output, input, metadata)\\n00520| M._format_action(output, icons.get('run') .. ' run', input and input.description)\\n00521| \\n00522| if not config.ui.output.tools.show_output then\\n00523| return\\n00524| end\\n00525| \\n00526| if metadata.output or metadata.command or input.command then\\n00527| local command = input.command or metadata.command or ''\\n00528| local command_output = metadata.output and metadata.output ~= '' and ('\\\\n' .. metadata.output) or ''\\n00529| M._format_code(output, vim.split('> ' .. command .. '\\\\n' .. command_output, '\\\\n'), 'bash')\\n00530| end\\n00531| end\\n00532| \\n00533| ---@param output Output Output object to write to\\n00534| ---@param tool_type string Tool type (e.g., 'read', 'edit', 'write')\\n00535| ---@param input FileToolInput data for the tool\\n00536| ---@param metadata FileToolMetadata Metadata for the tool use\\n00537| function M._format_file_tool(output, tool_type, input, metadata)\\n00538| local file_name = input and vim.fn.fnamemodify(input.filePath, ':t') or ''\\n00539| local file_type = input and util.get_markdown_filetype(input.filePath) or ''\\n00540| local tool_action_icons = { read = icons.get('read'), edit = icons.get('edit'), write = icons.get('write') }\\n00541| \\n00542| M._format_action(output, tool_action_icons[tool_type] .. ' ' .. tool_type, file_name)\\n00543| \\n00544| if not config.ui.output.tools.show_output then\\n00545| return\\n00546| end\\n00547| \\n00548| if tool_type == 'edit' and metadata.diff then\\n00549| M._format_diff(output, metadata.diff, file_type)\\n00550| elseif tool_type == 'write' and input and input.content then\\n00551| M._format_code(output, vim.split(input.content, '\\\\n'), file_type)\\n00552| end\\n00553| end\\n00554| \\n00555| ---@param output Output Output object to write to\\n00556| ---@param title string\\n00557| ---@param input TodoToolInput\\n00558| function M._format_todo_tool(output, title, input)\\n00559| M._format_action(output, icons.get('plan') .. ' plan', (title or ''))\\n00560| if not config.ui.output.tools.show_output then\\n00561| return\\n00562| end\\n00563| \\n00564| local todos = input and input.todos or {}\\n00565| \\n00566| for _, item in ipairs(todos) do\\n00567| local statuses = { in_progress = '-', completed = 'x', pending = ' ' }\\n00568| output:add_line(string.format('- [%s] %s ', statuses[item.status], item.content))\\n00569| end\\n00570| end\\n00571| \\n00572| ---@param output Output Output object to write to\\n00573| ---@param input GlobToolInput data for the tool\\n00574| ---@param metadata GlobToolMetadata Metadata for the tool use\\n00575| function M._format_glob_tool(output, input, metadata)\\n00576| M._format_action(output, icons.get('search') .. ' glob', input and input.pattern)\\n00577| if not config.ui.output.tools.show_output then\\n00578| return\\n00579| end\\n00580| local prefix = metadata.truncated and ' more than' or ''\\n00581| output:add_line(string.format('Found%s `%d` file(s):', prefix, metadata.count or 0))\\n00582| end\\n00583| \\n00584| ---@param output Output Output object to write to\\n00585| ---@param input GrepToolInput data for the tool\\n00586| ---@param metadata GrepToolMetadata Metadata for the tool use\\n00587| function M._format_grep_tool(output, input, metadata)\\n00588| input = input or { path = '', include = '', pattern = '' }\\n00589| \\n00590| local grep_str = string.format('%s` `%s', (input.path or input.include) or '', input.pattern or '')\\n00591| \\n00592| M._format_action(output, icons.get('search') .. ' grep', grep_str)\\n00593| if not config.ui.output.tools.show_output then\\n00594| return\\n00595| end\\n00596| local prefix = metadata.truncated and ' more than' or ''\\n00597| output:add_line(\\n00598| string.format('Found%s `%d` match' .. (metadata.matches ~= 1 and 'es' or ''), prefix, metadata.matches or 0)\\n00599| )\\n00600| end\\n00601| \\n00602| ---@param output Output Output object to write to\\n00603| ---@param input WebFetchToolInput data for the tool\\n00604| function M._format_webfetch_tool(output, input)\\n00605| M._format_action(output, icons.get('web') .. ' fetch', input and input.url)\\n00606| end\\n00607| \\n00608| ---@param output Output Output object to write to\\n00609| ---@param input ListToolInput\\n00610| ---@param metadata ListToolMetadata\\n00611| ---@param tool_output string\\n00612| function M._format_list_tool(output, input, metadata, tool_output)\\n00613| M._format_action(output, icons.get('list') .. ' list', input and input.path or '')\\n00614| if not config.ui.output.tools.show_output then\\n00615| return\\n00616| end\\n00617| local lines = vim.split(vim.trim(tool_output or ''), '\\\\n')\\n00618| if #lines < 1 or metadata.count == 0 then\\n00619| output:add_line('No files found.')\\n00620| return\\n00621| end\\n00622| if #lines > 1 then\\n00623| output:add_line('Files:')\\n00624| for i = 2, #lines do\\n00625| local file = vim.trim(lines[i])\\n00626| if file ~= '' then\\n00627| output:add_line(' • ' .. file)\\n00628| end\\n00629| end\\n00630| end\\n00631| if metadata.truncated then\\n00632| output:add_line(string.format('Results truncated, showing first %d files', metadata.count or '?'))\\n00633| end\\n00634| end\\n00635| \\n00636| ---@param output Output Output object to write to\\n00637| ---@param part OpencodeMessagePart\\n00638| function M._format_tool(output, part)\\n00639| local tool = part.tool\\n00640| if not tool or not part.state then\\n00641| return\\n00642| end\\n00643| \\n00644| local start_line = output:get_line_count() + 1\\n00645| local input = part.state.input or {}\\n00646| local metadata = part.state.metadata or {}\\n00647| local tool_output = part.state.output or ''\\n00648| \\n00649| if state.current_permission and state.current_permission.messageID == part.messageID then\\n00650| metadata = state.current_permission.metadata or metadata\\n00651| end\\n00652| \\n00653| if tool == 'bash' then\\n00654| M._format_bash_tool(output, input --[[@as BashToolInput]], metadata --[[@as BashToolMetadata]])\\n00655| elseif tool == 'read' or tool == 'edit' or tool == 'write' then\\n00656| M._format_file_tool(output, tool, input --[[@as FileToolInput]], metadata --[[@as FileToolMetadata]])\\n00657| elseif tool == 'todowrite' then\\n00658| M._format_todo_tool(output, part.state.title, input --[[@as TodoToolInput]])\\n00659| elseif tool == 'glob' then\\n00660| M._format_glob_tool(output, input --[[@as GlobToolInput]], metadata --[[@as GlobToolMetadata]])\\n00661| elseif tool == 'list' then\\n00662| M._format_list_tool(output, input --[[@as ListToolInput]], metadata --[[@as ListToolMetadata]], tool_output)\\n00663| elseif tool == 'grep' then\\n00664| M._format_grep_tool(output, input --[[@as GrepToolInput]], metadata --[[@as GrepToolMetadata]])\\n00665| elseif tool == 'webfetch' then\\n00666| M._format_webfetch_tool(output, input --[[@as WebFetchToolInput]])\\n00667| elseif tool == 'task' then\\n00668| M._format_task_tool(output, input --[[@as TaskToolInput]], metadata --[[@as TaskToolMetadata]], tool_output)\\n00669| else\\n00670| M._format_action(output, icons.get('tool') .. ' tool', tool)\\n00671| end\\n00672| \\n00673| if part.state.status == 'error' and part.state.error then\\n00674| output:add_line('')\\n00675| M._format_callout(output, 'ERROR', part.state.error)\\n00676| ---@diagnostic disable-next-line: undefined-field\\n00677| elseif part.state.input and part.state.input.error then\\n00678| output:add_line('')\\n00679| ---I'm not sure about the type with state.input.error\\n00680| ---@diagnostic disable-next-line: undefined-field\\n00681| M._format_callout(output, 'ERROR', part.state.input.error)\\n00682| end\\n00683| \\n00684| if\\n00685| state.current_permission\\n00686| and (\\n00687| (\\n00688| state.current_permission.tool\\n00689| and state.current_permission.tool.callID == part.callID\\n00690| and state.current_permission.tool.messageID == part.messageID\\n00691| )\\n00692| ---@TODO this is for backward compatibility, remove later\\n00693| or (state.current_permission.messageID == part.messageID and state.current_permission.callID == part.callID)\\n00694| )\\n00695| then\\n00696| M._handle_permission_request(output, part)\\n00697| end\\n00698| \\n00699| local end_line = output:get_line_count()\\n00700| if end_line - start_line > 1 then\\n00701| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1)\\n00702| end\\n00703| end\\n00704| \\n00705| ---@param output Output Output object to write to\\n00706| ---@param input TaskToolInput data for the tool\\n00707| ---@param metadata TaskToolMetadata Metadata for the tool use\\n00708| ---@param tool_output string\\n00709| function M._format_task_tool(output, input, metadata, tool_output)\\n00710| local start_line = output:get_line_count() + 1\\n00711| M._format_action(output, icons.get('task') .. ' task', input and input.description)\\n00712| \\n00713| if config.ui.output.tools.show_output then\\n00714| if tool_output and tool_output ~= '' then\\n00715| output:add_empty_line()\\n00716| output:add_lines(vim.split(tool_output, '\\\\n'))\\n00717| output:add_empty_line()\\n00718| end\\n00719| \\n00720| if metadata.summary and type(metadata.summary) == 'table' then\\n00721| for _, sub_part in ipairs(metadata.summary) do\\n00722| if sub_part.type == 'tool' and sub_part.tool then\\n00723| M._format_tool(output, sub_part)\\n00724| end\\n00725| end\\n00726| end\\n00727| end\\n00728| \\n00729| local end_line = output:get_line_count()\\n00730| output:add_action({\\n00731| text = '[S]elect Child Session',\\n00732| type = 'select_child_session',\\n00733| args = {},\\n00734| key = 'S',\\n00735| display_line = start_line - 1,\\n00736| range = { from = start_line, to = end_line },\\n00737| })\\n00738| end\\n00739| \\n00740| ---@param output Output Output object to write to\\n00741| ---@param lines string[]\\n00742| ---@param language string\\n00743| function M._format_code(output, lines, language)\\n00744| output:add_empty_line()\\n00745| --- NOTE: use longer code fence because lines could contain ```\\n00746| output:add_line('`````' .. (language or ''))\\n00747| output:add_lines(util.sanitize_lines(lines))\\n00748| output:add_line('`````')\\n00749| end\\n00750| \\n00751| ---@param output Output Output object to write to\\n00752| ---@param code string\\n00753| ---@param file_type string\\n00754| function M._format_diff(output, code, file_type)\\n00755| output:add_empty_line()\\n00756| \\n00757| --- NOTE: use longer code fence because code could contain ```\\n00758| output:add_line('`````' .. file_type)\\n00759| local lines = vim.split(code, '\\\\n')\\n00760| if #lines > 5 then\\n00761| lines = vim.list_slice(lines, 6)\\n00762| end\\n00763| \\n00764| for _, line in ipairs(lines) do\\n00765| local first_char = line:sub(1, 1)\\n00766| if first_char == '+' or first_char == '-' then\\n00767| local hl_group = first_char == '+' and 'OpencodeDiffAdd' or 'OpencodeDiffDelete'\\n00768| output:add_line(' ' .. line:sub(2))\\n00769| local line_idx = output:get_line_count()\\n00770| output:add_extmark(line_idx - 1, function()\\n00771| return {\\n00772| end_col = 0,\\n00773| end_row = line_idx,\\n00774| virt_text = { { first_char, hl_group } },\\n00775| hl_group = hl_group,\\n00776| hl_eol = true,\\n00777| priority = 5000,\\n00778| right_gravity = true,\\n00779| end_right_gravity = false,\\n00780| virt_text_hide = false,\\n00781| virt_text_pos = 'overlay',\\n00782| virt_text_repeat_linebreak = false,\\n00783| }\\n00784| end)\\n00785| else\\n00786| output:add_line(line)\\n00787| end\\n00788| end\\n00789| output:add_line('`````')\\n00790| end\\n00791| \\n00792| ---@param output Output Output object to write to\\n00793| ---@param start_line number\\n00794| ---@param end_line number\\n00795| ---@param hl_group string Highlight group for the border character\\n00796| ---@param win_col number\\n00797| ---@param text_hl_group? string Optional highlight group for the background/foreground of text lines\\n00798| function M._add_vertical_border(output, start_line, end_line, hl_group, win_col, text_hl_group)\\n00799| for line = start_line, end_line do\\n00800| local extmark_opts = {\\n00801| virt_text = { { require('opencode.ui.icons').get('border'), hl_group } },\\n00802| virt_text_pos = 'overlay',\\n00803| virt_text_win_col = win_col,\\n00804| virt_text_repeat_linebreak = true,\\n00805| }\\n00806| \\n00807| -- Add line highlight if text_hl_group is provided\\n00808| if text_hl_group then\\n00809| extmark_opts.line_hl_group = text_hl_group\\n00810| end\\n00811| \\n00812| output:add_extmark(line - 1, extmark_opts --[[@as OutputExtmark]])\\n00813| end\\n00814| end\\n00815| \\n00816| ---Formats a single message part and returns the resulting output object\\n00817| ---@param part OpencodeMessagePart The part to format\\n00818| ---@param message? OpencodeMessage Optional message object to extract role and mentions from\\n00819| ---@param is_last_part? boolean Whether this is the last part in the message, used to show an error if there is one\\n00820| ---@return Output\\n00821| function M.format_part(part, message, is_last_part)\\n00822| local output = Output.new()\\n00823| \\n00824| if not message or not message.info or not message.info.role then\\n00825| return output\\n00826| end\\n00827| \\n00828| local content_added = false\\n00829| local role = message.info.role\\n00830| \\n00831| if role == 'user' then\\n00832| if part.type == 'text' and part.text then\\n00833| if part.synthetic == true then\\n00834| M._format_selection_context(output, part)\\n00835| M._format_cursor_data_context(output, part)\\n00836| M._format_diagnostics_context(output, part)\\n00837| else\\n00838| M._format_user_prompt(output, vim.trim(part.text), message)\\n00839| content_added = true\\n00840| end\\n00841| elseif part.type == 'file' then\\n00842| local file_line = M._format_context_file(output, part.filename)\\n00843| if file_line then\\n00844| M._add_vertical_border(output, file_line - 1, file_line, 'OpencodeMessageRoleUser', -3)\\n00845| content_added = true\\n00846| end\\n00847| end\\n00848| elseif role == 'assistant' then\\n00849| if part.type == 'text' and part.text then\\n00850| M._format_assistant_message(output, vim.trim(part.text))\\n00851| content_added = true\\n00852| elseif part.type == 'reasoning' and part.text then\\n00853| M._format_reasoning(output, part)\\n00854| content_added = true\\n00855| elseif part.type == 'tool' then\\n00856| M._format_tool(output, part)\\n00857| content_added = true\\n00858| elseif part.type == 'patch' and part.hash then\\n00859| M._format_patch(output, part)\\n00860| content_added = true\\n00861| end\\n00862| end\\n00863| \\n00864| if content_added then\\n00865| output:add_empty_line()\\n00866| end\\n00867| \\n00868| if is_last_part and role == 'assistant' and message.info.error and message.info.error ~= '' then\\n00869| local error = message.info.error\\n00870| local error_message = error.data and error.data.message or vim.inspect(error)\\n00871| M._format_callout(output, 'ERROR', error_message)\\n00872| output:add_empty_line()\\n00873| end\\n00874| \\n00875| return output\\n00876| end\\n00877| \\n00878| return M\\n00879| \\n\\n(End of file - total 879 lines)\\n\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"file\",\"url\":\"file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\",\"id\":\"prt_b8e7c60a7002ybV09VDHoQQeO7\",\"filename\":\"lua/opencode/ui/formatter.lua\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"mime\":\"text/plain\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3002XHHlk77vAPApvR\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"{\\\"content\\\":[{\\\"msg\\\":\\\"expected `SessionRevertInfo` but found `SessionRevertInfo?`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l156:c68\\\"},{\\\"msg\\\":\\\"expected `integer?` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l490:c43\\\"},{\\\"msg\\\":\\\"expected `integer` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l492:c45\\\"},{\\\"msg\\\":\\\"expected `integer?` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l492:c62\\\"},{\\\"msg\\\":\\\"state.active_session may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l156:c68\\\"},{\\\"msg\\\":\\\"state.messages[#state.messages] may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l272:c74\\\"},{\\\"msg\\\":\\\"state.messages may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l272:c74\\\"},{\\\"msg\\\":\\\"Undefined field `[diag.severity]`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l435:c42\\\"},{\\\"msg\\\":\\\"Undefined field `command`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l526:c34\\\"},{\\\"msg\\\":\\\"Undefined field `command`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l527:c47\\\"},{\\\"msg\\\":\\\"Cannot assign `number` to `integer`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l493:c5\\\"}],\\\"context_type\\\":\\\"diagnostics\\\"}\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"time\":{\"updated\":1767622074603,\"created\":1767622072149}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"providerID\":\"github-copilot\",\"role\":\"assistant\",\"path\":{\"root\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"cwd\":\"/home/francis/Projects/_nvim/opencode.nvim\"},\"agent\":\"build\",\"time\":{\"created\":1767622074609},\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"mode\":\"build\",\"modelID\":\"gpt-4.1\",\"id\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"parentID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"cost\":0,\"tokens\":{\"output\":0,\"reasoning\":0,\"input\":0,\"cache\":{\"write\":0,\"read\":0}}}},\"type\":\"message.updated\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"created\":1767622074530},\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"summary\":{\"diffs\":[]}}},\"type\":\"message.updated\"},{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"updated\":1767622074670,\"created\":1767622072149},\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"summary\":{\"deletions\":0,\"additions\":0,\"files\":0}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"step-start\",\"id\":\"prt_b8e7c6672001F10WAiQKbzNEtE\",\"snapshot\":\"5ba6e95774829e7f501299039b72b72dc32c6620\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"tool\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"id\":\"prt_b8e7c6686001cCV44vsFtbpF42\",\"state\":{\"status\":\"pending\",\"input\":{},\"raw\":\"\"},\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\",\"tool\":\"bash\"}},\"type\":\"message.part.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"tool\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"id\":\"prt_b8e7c6686001cCV44vsFtbpF42\",\"state\":{\"status\":\"running\",\"input\":{\"description\":\"Shows working tree status\",\"command\":\"git status\"},\"time\":{\"start\":1767622076189}},\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\",\"tool\":\"bash\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"tool\":{\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\"},\"patterns\":[\"git status\"],\"id\":\"per_b8e7c6744001DX6EZ9KHM15RLi\",\"permission\":\"bash\",\"always\":[\"git status*\"],\"metadata\":{}},\"type\":\"permission.asked\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"created\":1767622074530},\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"summary\":{\"title\":\"Running git status to list changed files\",\"diffs\":[]}}},\"type\":\"message.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"title\":\"Running git status for formatter.lua changes\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"updated\":1767622082619,\"created\":1767622072149},\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"summary\":{\"deletions\":0,\"additions\":0,\"files\":0}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"}]\n","before":"","deletions":0,"additions":1}],"body":"I updated the UI and event handling code by modifying `file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/event_manager.lua`, `file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua`, and `file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/renderer.lua` to improve formatting and rendering behavior. I also added `file:///home/francis/Projects/_nvim/opencode.nvim/test.lua` and `file:///home/francis/Projects/_nvim/opencode.nvim/tests/data/permission_ask_new.json` as new test/data files."}}},"type":"message.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"}]
+[
+ {
+ "properties": {
+ "info": {
+ "title": "New session - 2026-01-05T14:07:52.149Z",
+ "version": "1.1.2",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "time": { "updated": 1767622072149, "created": 1767622072149 }
+ }
+ },
+ "type": "session.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "role": "user",
+ "id": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "agent": "build",
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "time": { "created": 1767622074530 }
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "id": "prt_b8e7c60a3001M2zsH9REfPdlQt",
+ "text": "@no-trust run a git status and tell me what files are changed",
+ "messageID": "msg_b8e7c60a2001Kisjwk2mVB4dye"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "id": "prt_b8e7c60a3003Ta9NcXkN0lb0lF",
+ "messageID": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "text": "Called the Read tool with the following input: {\"filePath\":\"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\"}",
+ "synthetic": true
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "id": "prt_b8e7c60a7001d3WhKOu2vCR4Cf",
+ "messageID": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "text": "\n00001| local context_module = require('opencode.context')\n00002| local icons = require('opencode.ui.icons')\n00003| local util = require('opencode.util')\n00004| local Output = require('opencode.ui.output')\n00005| local state = require('opencode.state')\n00006| local config = require('opencode.config')\n00007| local snapshot = require('opencode.snapshot')\n00008| local mention = require('opencode.ui.mention')\n00009| \n00010| local M = {}\n00011| \n00012| M.separator = {\n00013| '----',\n00014| '',\n00015| }\n00016| \n00017| ---@param output Output\n00018| ---@param part OpencodeMessagePart\n00019| function M._format_reasoning(output, part)\n00020| local text = vim.trim(part.text or '')\n00021| if text == '' then\n00022| return\n00023| end\n00024| \n00025| local start_line = output:get_line_count() + 1\n00026| \n00027| local title = 'Reasoning'\n00028| local time = part.time\n00029| if time and type(time) == 'table' and time.start then\n00030| local start_text = util.format_time(time.start) or ''\n00031| local end_text = (time['end'] and util.format_time(time['end'])) or nil\n00032| if end_text and end_text ~= '' then\n00033| title = string.format('%s (%s - %s)', title, start_text, end_text)\n00034| elseif start_text ~= '' then\n00035| title = string.format('%s (%s)', title, start_text)\n00036| end\n00037| end\n00038| \n00039| M._format_action(output, icons.get('reasoning') .. ' ' .. title, '')\n00040| \n00041| if config.ui.output.tools.show_reasoning_output then\n00042| output:add_empty_line()\n00043| output:add_lines(vim.split(text, '\\n'))\n00044| output:add_empty_line()\n00045| end\n00046| \n00047| local end_line = output:get_line_count()\n00048| if end_line - start_line > 1 then\n00049| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1, 'OpencodeReasoningText')\n00050| else\n00051| output:add_extmark(start_line - 1, {\n00052| line_hl_group = 'OpencodeReasoningText',\n00053| } --[[@as OutputExtmark]])\n00054| end\n00055| end\n00056| \n00057| function M._handle_permission_request(output, part)\n00058| if part.state and part.state.status == 'error' and part.state.error then\n00059| if part.state.error:match('rejected permission') then\n00060| state.current_permission = nil\n00061| else\n00062| vim.notify('Unknown part state error: ' .. part.state.error)\n00063| end\n00064| return\n00065| end\n00066| \n00067| M._format_permission_request(output)\n00068| end\n00069| \n00070| function M._format_permission_request(output)\n00071| local keys\n00072| \n00073| if require('opencode.ui.ui').is_opencode_focused() then\n00074| keys = {\n00075| config.keymap.permission.accept,\n00076| config.keymap.permission.accept_all,\n00077| config.keymap.permission.deny,\n00078| }\n00079| else\n00080| keys = {\n00081| config.get_key_for_function('editor', 'permission_accept'),\n00082| config.get_key_for_function('editor', 'permission_accept_all'),\n00083| config.get_key_for_function('editor', 'permission_deny'),\n00084| }\n00085| end\n00086| \n00087| output:add_empty_line()\n00088| output:add_line('> [!WARNING] Permission required to run this tool.')\n00089| output:add_line('>')\n00090| output:add_line(('> Accept `%s` Always `%s` Deny `%s`'):format(unpack(keys)))\n00091| output:add_empty_line()\n00092| end\n00093| \n00094| ---Calculate statistics for reverted messages and tool calls\n00095| ---@param messages {info: MessageInfo, parts: OpencodeMessagePart[]}[] All messages in the session\n00096| ---@param revert_index number Index of the message where revert occurred\n00097| ---@param revert_info SessionRevertInfo Revert information\n00098| ---@return {messages: number, tool_calls: number, files: table}\n00099| function M._calculate_revert_stats(messages, revert_index, revert_info)\n00100| local stats = {\n00101| messages = 0,\n00102| tool_calls = 0,\n00103| files = {}, -- { [filename] = { additions = n, deletions = m } }\n00104| }\n00105| \n00106| for i = revert_index, #messages do\n00107| local msg = messages[i]\n00108| if msg.info.role == 'user' then\n00109| stats.messages = stats.messages + 1\n00110| end\n00111| if msg.parts then\n00112| for _, part in ipairs(msg.parts) do\n00113| if part.type == 'tool' then\n00114| stats.tool_calls = stats.tool_calls + 1\n00115| end\n00116| end\n00117| end\n00118| end\n00119| \n00120| if revert_info.diff then\n00121| local current_file = nil\n00122| for line in revert_info.diff:gmatch('[^\\r\\n]+') do\n00123| local file_a = line:match('^%-%-%- ([ab]/.+)')\n00124| local file_b = line:match('^%+%+%+ ([ab]/.+)')\n00125| if file_b then\n00126| current_file = file_b:gsub('^[ab]/', '')\n00127| if not stats.files[current_file] then\n00128| stats.files[current_file] = { additions = 0, deletions = 0 }\n00129| end\n00130| elseif file_a then\n00131| current_file = file_a:gsub('^[ab]/', '')\n00132| if not stats.files[current_file] then\n00133| stats.files[current_file] = { additions = 0, deletions = 0 }\n00134| end\n00135| elseif line:sub(1, 1) == '+' and not line:match('^%+%+%+') then\n00136| if current_file then\n00137| stats.files[current_file].additions = stats.files[current_file].additions + 1\n00138| end\n00139| elseif line:sub(1, 1) == '-' and not line:match('^%-%-%-') then\n00140| if current_file then\n00141| stats.files[current_file].deletions = stats.files[current_file].deletions + 1\n00142| end\n00143| end\n00144| end\n00145| end\n00146| \n00147| return stats\n00148| end\n00149| \n00150| ---Format the revert callout with statistics\n00151| ---@param session_data OpencodeMessage[] All messages in the session\n00152| ---@param start_idx number Index of the message where revert occurred\n00153| ---@return Output output object representing the lines, extmarks, and actions\n00154| function M._format_revert_message(session_data, start_idx)\n00155| local output = Output.new()\n00156| local stats = M._calculate_revert_stats(session_data, start_idx, state.active_session.revert)\n00157| local message_text = stats.messages == 1 and 'message' or 'messages'\n00158| local tool_text = stats.tool_calls == 1 and 'tool call' or 'tool calls'\n00159| \n00160| output:add_lines(M.separator)\n00161| output:add_line(\n00162| string.format('> %d %s reverted, %d %s reverted', stats.messages, message_text, stats.tool_calls, tool_text)\n00163| )\n00164| output:add_line('>')\n00165| output:add_line('> type `/redo` to restore.')\n00166| output:add_empty_line()\n00167| \n00168| if stats.files and next(stats.files) then\n00169| for file, fstats in pairs(stats.files) do\n00170| local file_diff = {}\n00171| if fstats.additions > 0 then\n00172| table.insert(file_diff, '+' .. fstats.additions)\n00173| end\n00174| if fstats.deletions > 0 then\n00175| table.insert(file_diff, '-' .. fstats.deletions)\n00176| end\n00177| if #file_diff > 0 then\n00178| local line_str = string.format(icons.get('file') .. '%s: %s', file, table.concat(file_diff, ' '))\n00179| local line_idx = output:add_line(line_str)\n00180| local col = #(' ' .. file .. ': ')\n00181| for _, diff in ipairs(file_diff) do\n00182| local hl_group = diff:sub(1, 1) == '+' and 'OpencodeDiffAddText' or 'OpencodeDiffDeleteText'\n00183| output:add_extmark(line_idx - 1, {\n00184| virt_text = { { diff, hl_group } },\n00185| virt_text_pos = 'inline',\n00186| virt_text_win_col = col,\n00187| priority = 1000,\n00188| } --[[@as OutputExtmark]])\n00189| col = col + #diff + 1\n00190| end\n00191| end\n00192| end\n00193| end\n00194| return output\n00195| end\n00196| \n00197| local function add_action(output, text, action_type, args, key, line)\n00198| -- actions use api-indexing (e.g. 0 indexed)\n00199| line = (line or output:get_line_count()) - 1\n00200| output:add_action({\n00201| text = text,\n00202| type = action_type,\n00203| args = args,\n00204| key = key,\n00205| display_line = line,\n00206| range = { from = line, to = line },\n00207| })\n00208| end\n00209| \n00210| ---@param output Output Output object to write to\n00211| ---@param part OpencodeMessagePart\n00212| function M._format_patch(output, part)\n00213| if not part.hash then\n00214| return\n00215| end\n00216| \n00217| local restore_points = snapshot.get_restore_points_by_parent(part.hash) or {}\n00218| M._format_action(output, icons.get('snapshot') .. ' Created Snapshot', vim.trim(part.hash:sub(1, 8)))\n00219| \n00220| -- Anchor all snapshot-level actions to the snapshot header line\n00221| add_action(output, '[R]evert file', 'diff_revert_selected_file', { part.hash }, 'R')\n00222| add_action(output, 'Revert [A]ll', 'diff_revert_all', { part.hash }, 'A')\n00223| add_action(output, '[D]iff', 'diff_open', { part.hash }, 'D')\n00224| \n00225| if #restore_points > 0 then\n00226| for _, restore_point in ipairs(restore_points) do\n00227| output:add_line(\n00228| string.format(\n00229| ' %s Restore point `%s` - %s ',\n00230| icons.get('restore_point'),\n00231| vim.trim(restore_point.id:sub(1, 8)),\n00232| util.format_time(restore_point.created_at)\n00233| )\n00234| )\n00235| add_action(output, 'Restore [A]ll', 'diff_restore_snapshot_all', { restore_point.id }, 'A')\n00236| add_action(output, '[R]estore file', 'diff_restore_snapshot_file', { restore_point.id }, 'R')\n00237| end\n00238| end\n00239| end\n00240| \n00241| ---@param output Output Output object to write to\n00242| ---@param message MessageInfo\n00243| function M._format_error(output, message)\n00244| output:add_empty_line()\n00245| M._format_callout(output, 'ERROR', vim.inspect(message.error))\n00246| end\n00247| \n00248| ---@param message OpencodeMessage\n00249| ---@return Output\n00250| function M.format_message_header(message)\n00251| local output = Output.new()\n00252| \n00253| output:add_lines(M.separator)\n00254| local role = message.info.role or 'unknown'\n00255| local icon = message.info.role == 'user' and icons.get('header_user') or icons.get('header_assistant')\n00256| \n00257| local time = message.info.time and message.info.time.created or nil\n00258| local time_text = (time and ' (' .. util.format_time(time) .. ')' or '')\n00259| local role_hl = 'OpencodeMessageRole' .. role:sub(1, 1):upper() .. role:sub(2)\n00260| local model_text = message.info.modelID and ' ' .. message.info.modelID or ''\n00261| \n00262| local debug_text = config.debug.show_ids and ' [' .. message.info.id .. ']' or ''\n00263| \n00264| local display_name\n00265| if role == 'assistant' then\n00266| local mode = message.info.mode\n00267| if mode and mode ~= '' then\n00268| display_name = mode:upper()\n00269| else\n00270| -- For the most recent assistant message, show current_mode if mode is missing\n00271| -- This handles new messages that haven't been stamped yet\n00272| local is_last_message = #state.messages == 0 or message.info.id == state.messages[#state.messages].info.id\n00273| if is_last_message and state.current_mode and state.current_mode ~= '' then\n00274| display_name = state.current_mode:upper()\n00275| else\n00276| display_name = 'ASSISTANT'\n00277| end\n00278| end\n00279| else\n00280| display_name = role:upper()\n00281| end\n00282| \n00283| output:add_extmark(output:get_line_count() - 1, {\n00284| virt_text = {\n00285| { icon, role_hl },\n00286| { ' ' },\n00287| { display_name, role_hl },\n00288| { model_text, 'OpencodeHint' },\n00289| { time_text, 'OpencodeHint' },\n00290| { debug_text, 'OpencodeHint' },\n00291| },\n00292| virt_text_win_col = -3,\n00293| priority = 10,\n00294| } --[[@as OutputExtmark]])\n00295| \n00296| -- Only want to show the error if we have no parts. If we have parts, they'll\n00297| -- handle rendering the error\n00298| if\n00299| role == 'assistant'\n00300| and message.info.error\n00301| and message.info.error ~= ''\n00302| and (not message.parts or #message.parts == 0)\n00303| then\n00304| local error = message.info.error\n00305| local error_message = error.data and error.data.message or vim.inspect(error)\n00306| \n00307| output:add_line('')\n00308| M._format_callout(output, 'ERROR', error_message)\n00309| end\n00310| \n00311| output:add_line('')\n00312| return output\n00313| end\n00314| \n00315| ---@param output Output Output object to write to\n00316| ---@param callout string Callout type (e.g., 'ERROR', 'TODO')\n00317| ---@param text string Callout text content\n00318| ---@param title? string Optional title for the callout\n00319| function M._format_callout(output, callout, text, title)\n00320| title = title and title .. ' ' or ''\n00321| local win_width = (state.windows and state.windows.output_win and vim.api.nvim_win_is_valid(state.windows.output_win))\n00322| and vim.api.nvim_win_get_width(state.windows.output_win)\n00323| or config.ui.window_width\n00324| or 80\n00325| if #text > win_width - 4 then\n00326| local ok, substituted = pcall(vim.fn.substitute, text, '\\v(.{' .. (win_width - 8) .. '})', '\\1\\n', 'g')\n00327| text = ok and substituted or text\n00328| end\n00329| \n00330| -- Trim off any trailing newlines so there isn't an extra line in the\n00331| -- extmarks section\n00332| local lines = vim.split(text:gsub('\\n$', ''), '\\n')\n00333| if #lines == 1 and title == '' then\n00334| output:add_line('> [!' .. callout .. '] ' .. lines[1])\n00335| else\n00336| output:add_line('> [!' .. callout .. ']' .. title)\n00337| output:add_line('>')\n00338| output:add_lines(lines, '> ')\n00339| end\n00340| end\n00341| \n00342| ---@param output Output Output object to write to\n00343| ---@param text string\n00344| ---@param message? OpencodeMessage Optional message object to extract mentions from\n00345| function M._format_user_prompt(output, text, message)\n00346| local start_line = output:get_line_count()\n00347| \n00348| output:add_lines(vim.split(text, '\\n'))\n00349| \n00350| local end_line = output:get_line_count()\n00351| \n00352| local end_line_extmark_offset = 0\n00353| \n00354| local mentions = {}\n00355| if message and message.parts then\n00356| -- message.parts will only be filled out on a re-render\n00357| -- we need to collect the mentions here\n00358| for _, part in ipairs(message.parts) do\n00359| if part.type == 'file' then\n00360| -- we're rerendering this part and we have files, the space after the user prompt\n00361| -- also needs an extmark\n00362| end_line_extmark_offset = 1\n00363| if part.source and part.source.text then\n00364| table.insert(mentions, part.source.text)\n00365| end\n00366| elseif part.type == 'agent' then\n00367| if part.source then\n00368| table.insert(mentions, part.source)\n00369| end\n00370| end\n00371| end\n00372| end\n00373| \n00374| if #mentions > 0 then\n00375| mention.highlight_mentions_in_output(output, text, mentions, start_line)\n00376| end\n00377| \n00378| M._add_vertical_border(output, start_line, end_line + end_line_extmark_offset, 'OpencodeMessageRoleUser', -3)\n00379| end\n00380| \n00381| ---@param output Output Output object to write to\n00382| ---@param part OpencodeMessagePart\n00383| function M._format_selection_context(output, part)\n00384| local json = context_module.decode_json_context(part.text or '', 'selection')\n00385| if not json then\n00386| return\n00387| end\n00388| local start_line = output:get_line_count()\n00389| output:add_lines(vim.split(json.content or '', '\\n'))\n00390| output:add_empty_line()\n00391| \n00392| local end_line = output:get_line_count()\n00393| \n00394| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00395| end\n00396| \n00397| ---@param output Output Output object to write to\n00398| ---@param part OpencodeMessagePart\n00399| function M._format_cursor_data_context(output, part)\n00400| local json = context_module.decode_json_context(part.text or '', 'cursor-data')\n00401| if not json then\n00402| return\n00403| end\n00404| local start_line = output:get_line_count()\n00405| output:add_line('Line ' .. json.line .. ':')\n00406| output:add_lines(vim.split(json.line_content or '', '\\n'))\n00407| output:add_empty_line()\n00408| \n00409| local end_line = output:get_line_count()\n00410| \n00411| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00412| end\n00413| \n00414| ---@param output Output Output object to write to\n00415| ---@param part OpencodeMessagePart\n00416| function M._format_diagnostics_context(output, part)\n00417| local json = context_module.decode_json_context(part.text or '', 'diagnostics')\n00418| if not json then\n00419| return\n00420| end\n00421| local start_line = output:get_line_count()\n00422| local diagnostics = json.content --[[@as OpencodeDiagnostic[] ]]\n00423| if not diagnostics or type(diagnostics) ~= 'table' or #diagnostics == 0 then\n00424| return\n00425| end\n00426| \n00427| local diagnostics_count = { error = 0, warn = 0, info = 0 }\n00428| local diagnostics_icons = {\n00429| error = icons.get('error'),\n00430| warn = icons.get('warning'),\n00431| info = icons.get('info'),\n00432| }\n00433| \n00434| for _, diag in ipairs(diagnostics) do\n00435| local name = vim.diagnostic.severity[diag.severity]:lower()\n00436| diagnostics_count[name] = diagnostics_count[name] + 1\n00437| end\n00438| \n00439| local diag_line = '**Diagnostics:**'\n00440| for name, count in pairs(diagnostics_count) do\n00441| if count > 0 then\n00442| diag_line = diag_line .. (string.format(' %s(%d)', diagnostics_icons[name], count))\n00443| end\n00444| end\n00445| output:add_line(diag_line)\n00446| output:add_empty_line()\n00447| local end_line = output:get_line_count()\n00448| \n00449| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00450| end\n00451| \n00452| ---Format and display the file path in the context\n00453| ---@param output Output Output object to write to\n00454| ---@param path string|nil File path\n00455| function M._format_context_file(output, path)\n00456| if not path or path == '' then\n00457| return\n00458| end\n00459| local cwd = vim.fn.getcwd()\n00460| if vim.startswith(path, cwd) then\n00461| path = path:sub(#cwd + 2)\n00462| end\n00463| return output:add_line(string.format('[%s](%s)', path, path))\n00464| end\n00465| \n00466| ---@param output Output Output object to write to\n00467| ---@param text string\n00468| function M._format_assistant_message(output, text)\n00469| local reference_picker = require('opencode.ui.reference_picker')\n00470| local references = reference_picker.parse_references(text, '')\n00471| \n00472| -- If no references, just add the text as-is\n00473| if #references == 0 then\n00474| output:add_lines(vim.split(text, '\\n'))\n00475| return\n00476| end\n00477| \n00478| -- Sort references by match_start position (ascending)\n00479| table.sort(references, function(a, b)\n00480| return a.match_start < b.match_start\n00481| end)\n00482| \n00483| -- Build a new text with icons inserted before each reference\n00484| local result = ''\n00485| local last_pos = 1\n00486| local ref_icon = icons.get('reference')\n00487| \n00488| for _, ref in ipairs(references) do\n00489| -- Add text before this reference\n00490| result = result .. text:sub(last_pos, ref.match_start - 1)\n00491| -- Add the icon and the reference\n00492| result = result .. ref_icon .. text:sub(ref.match_start, ref.match_end)\n00493| last_pos = ref.match_end + 1\n00494| end\n00495| \n00496| -- Add any remaining text after the last reference\n00497| if last_pos <= #text then\n00498| result = result .. text:sub(last_pos)\n00499| end\n00500| \n00501| output:add_lines(vim.split(result, '\\n'))\n00502| end\n00503| \n00504| ---@param output Output Output object to write to\n00505| ---@param tool_type string Tool type (e.g., 'run', 'read', 'edit', etc.)\n00506| ---@param value string Value associated with the action (e.g., filename, command)\n00507| function M._format_action(output, tool_type, value)\n00508| if not tool_type or not value then\n00509| return\n00510| end\n00511| local line = string.format('**%s** %s', tool_type, value and #value > 0 and ('`' .. value .. '`') or '')\n00512| \n00513| output:add_line(line)\n00514| end\n00515| \n00516| ---@param output Output Output object to write to\n00517| ---@param input BashToolInput data for the tool\n00518| ---@param metadata BashToolMetadata Metadata for the tool use\n00519| function M._format_bash_tool(output, input, metadata)\n00520| M._format_action(output, icons.get('run') .. ' run', input and input.description)\n00521| \n00522| if not config.ui.output.tools.show_output then\n00523| return\n00524| end\n00525| \n00526| if metadata.output or metadata.command or input.command then\n00527| local command = input.command or metadata.command or ''\n00528| local command_output = metadata.output and metadata.output ~= '' and ('\\n' .. metadata.output) or ''\n00529| M._format_code(output, vim.split('> ' .. command .. '\\n' .. command_output, '\\n'), 'bash')\n00530| end\n00531| end\n00532| \n00533| ---@param output Output Output object to write to\n00534| ---@param tool_type string Tool type (e.g., 'read', 'edit', 'write')\n00535| ---@param input FileToolInput data for the tool\n00536| ---@param metadata FileToolMetadata Metadata for the tool use\n00537| function M._format_file_tool(output, tool_type, input, metadata)\n00538| local file_name = input and vim.fn.fnamemodify(input.filePath, ':t') or ''\n00539| local file_type = input and util.get_markdown_filetype(input.filePath) or ''\n00540| local tool_action_icons = { read = icons.get('read'), edit = icons.get('edit'), write = icons.get('write') }\n00541| \n00542| M._format_action(output, tool_action_icons[tool_type] .. ' ' .. tool_type, file_name)\n00543| \n00544| if not config.ui.output.tools.show_output then\n00545| return\n00546| end\n00547| \n00548| if tool_type == 'edit' and metadata.diff then\n00549| M._format_diff(output, metadata.diff, file_type)\n00550| elseif tool_type == 'write' and input and input.content then\n00551| M._format_code(output, vim.split(input.content, '\\n'), file_type)\n00552| end\n00553| end\n00554| \n00555| ---@param output Output Output object to write to\n00556| ---@param title string\n00557| ---@param input TodoToolInput\n00558| function M._format_todo_tool(output, title, input)\n00559| M._format_action(output, icons.get('plan') .. ' plan', (title or ''))\n00560| if not config.ui.output.tools.show_output then\n00561| return\n00562| end\n00563| \n00564| local todos = input and input.todos or {}\n00565| \n00566| for _, item in ipairs(todos) do\n00567| local statuses = { in_progress = '-', completed = 'x', pending = ' ' }\n00568| output:add_line(string.format('- [%s] %s ', statuses[item.status], item.content))\n00569| end\n00570| end\n00571| \n00572| ---@param output Output Output object to write to\n00573| ---@param input GlobToolInput data for the tool\n00574| ---@param metadata GlobToolMetadata Metadata for the tool use\n00575| function M._format_glob_tool(output, input, metadata)\n00576| M._format_action(output, icons.get('search') .. ' glob', input and input.pattern)\n00577| if not config.ui.output.tools.show_output then\n00578| return\n00579| end\n00580| local prefix = metadata.truncated and ' more than' or ''\n00581| output:add_line(string.format('Found%s `%d` file(s):', prefix, metadata.count or 0))\n00582| end\n00583| \n00584| ---@param output Output Output object to write to\n00585| ---@param input GrepToolInput data for the tool\n00586| ---@param metadata GrepToolMetadata Metadata for the tool use\n00587| function M._format_grep_tool(output, input, metadata)\n00588| input = input or { path = '', include = '', pattern = '' }\n00589| \n00590| local grep_str = string.format('%s` `%s', (input.path or input.include) or '', input.pattern or '')\n00591| \n00592| M._format_action(output, icons.get('search') .. ' grep', grep_str)\n00593| if not config.ui.output.tools.show_output then\n00594| return\n00595| end\n00596| local prefix = metadata.truncated and ' more than' or ''\n00597| output:add_line(\n00598| string.format('Found%s `%d` match' .. (metadata.matches ~= 1 and 'es' or ''), prefix, metadata.matches or 0)\n00599| )\n00600| end\n00601| \n00602| ---@param output Output Output object to write to\n00603| ---@param input WebFetchToolInput data for the tool\n00604| function M._format_webfetch_tool(output, input)\n00605| M._format_action(output, icons.get('web') .. ' fetch', input and input.url)\n00606| end\n00607| \n00608| ---@param output Output Output object to write to\n00609| ---@param input ListToolInput\n00610| ---@param metadata ListToolMetadata\n00611| ---@param tool_output string\n00612| function M._format_list_tool(output, input, metadata, tool_output)\n00613| M._format_action(output, icons.get('list') .. ' list', input and input.path or '')\n00614| if not config.ui.output.tools.show_output then\n00615| return\n00616| end\n00617| local lines = vim.split(vim.trim(tool_output or ''), '\\n')\n00618| if #lines < 1 or metadata.count == 0 then\n00619| output:add_line('No files found.')\n00620| return\n00621| end\n00622| if #lines > 1 then\n00623| output:add_line('Files:')\n00624| for i = 2, #lines do\n00625| local file = vim.trim(lines[i])\n00626| if file ~= '' then\n00627| output:add_line(' • ' .. file)\n00628| end\n00629| end\n00630| end\n00631| if metadata.truncated then\n00632| output:add_line(string.format('Results truncated, showing first %d files', metadata.count or '?'))\n00633| end\n00634| end\n00635| \n00636| ---@param output Output Output object to write to\n00637| ---@param part OpencodeMessagePart\n00638| function M._format_tool(output, part)\n00639| local tool = part.tool\n00640| if not tool or not part.state then\n00641| return\n00642| end\n00643| \n00644| local start_line = output:get_line_count() + 1\n00645| local input = part.state.input or {}\n00646| local metadata = part.state.metadata or {}\n00647| local tool_output = part.state.output or ''\n00648| \n00649| if state.current_permission and state.current_permission.messageID == part.messageID then\n00650| metadata = state.current_permission.metadata or metadata\n00651| end\n00652| \n00653| if tool == 'bash' then\n00654| M._format_bash_tool(output, input --[[@as BashToolInput]], metadata --[[@as BashToolMetadata]])\n00655| elseif tool == 'read' or tool == 'edit' or tool == 'write' then\n00656| M._format_file_tool(output, tool, input --[[@as FileToolInput]], metadata --[[@as FileToolMetadata]])\n00657| elseif tool == 'todowrite' then\n00658| M._format_todo_tool(output, part.state.title, input --[[@as TodoToolInput]])\n00659| elseif tool == 'glob' then\n00660| M._format_glob_tool(output, input --[[@as GlobToolInput]], metadata --[[@as GlobToolMetadata]])\n00661| elseif tool == 'list' then\n00662| M._format_list_tool(output, input --[[@as ListToolInput]], metadata --[[@as ListToolMetadata]], tool_output)\n00663| elseif tool == 'grep' then\n00664| M._format_grep_tool(output, input --[[@as GrepToolInput]], metadata --[[@as GrepToolMetadata]])\n00665| elseif tool == 'webfetch' then\n00666| M._format_webfetch_tool(output, input --[[@as WebFetchToolInput]])\n00667| elseif tool == 'task' then\n00668| M._format_task_tool(output, input --[[@as TaskToolInput]], metadata --[[@as TaskToolMetadata]], tool_output)\n00669| else\n00670| M._format_action(output, icons.get('tool') .. ' tool', tool)\n00671| end\n00672| \n00673| if part.state.status == 'error' and part.state.error then\n00674| output:add_line('')\n00675| M._format_callout(output, 'ERROR', part.state.error)\n00676| ---@diagnostic disable-next-line: undefined-field\n00677| elseif part.state.input and part.state.input.error then\n00678| output:add_line('')\n00679| ---I'm not sure about the type with state.input.error\n00680| ---@diagnostic disable-next-line: undefined-field\n00681| M._format_callout(output, 'ERROR', part.state.input.error)\n00682| end\n00683| \n00684| if\n00685| state.current_permission\n00686| and (\n00687| (\n00688| state.current_permission.tool\n00689| and state.current_permission.tool.callID == part.callID\n00690| and state.current_permission.tool.messageID == part.messageID\n00691| )\n00692| ---@TODO this is for backward compatibility, remove later\n00693| or (state.current_permission.messageID == part.messageID and state.current_permission.callID == part.callID)\n00694| )\n00695| then\n00696| M._handle_permission_request(output, part)\n00697| end\n00698| \n00699| local end_line = output:get_line_count()\n00700| if end_line - start_line > 1 then\n00701| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1)\n00702| end\n00703| end\n00704| \n00705| ---@param output Output Output object to write to\n00706| ---@param input TaskToolInput data for the tool\n00707| ---@param metadata TaskToolMetadata Metadata for the tool use\n00708| ---@param tool_output string\n00709| function M._format_task_tool(output, input, metadata, tool_output)\n00710| local start_line = output:get_line_count() + 1\n00711| M._format_action(output, icons.get('task') .. ' task', input and input.description)\n00712| \n00713| if config.ui.output.tools.show_output then\n00714| if tool_output and tool_output ~= '' then\n00715| output:add_empty_line()\n00716| output:add_lines(vim.split(tool_output, '\\n'))\n00717| output:add_empty_line()\n00718| end\n00719| \n00720| if metadata.summary and type(metadata.summary) == 'table' then\n00721| for _, sub_part in ipairs(metadata.summary) do\n00722| if sub_part.type == 'tool' and sub_part.tool then\n00723| M._format_tool(output, sub_part)\n00724| end\n00725| end\n00726| end\n00727| end\n00728| \n00729| local end_line = output:get_line_count()\n00730| output:add_action({\n00731| text = '[S]elect Child Session',\n00732| type = 'select_child_session',\n00733| args = {},\n00734| key = 'S',\n00735| display_line = start_line - 1,\n00736| range = { from = start_line, to = end_line },\n00737| })\n00738| end\n00739| \n00740| ---@param output Output Output object to write to\n00741| ---@param lines string[]\n00742| ---@param language string\n00743| function M._format_code(output, lines, language)\n00744| output:add_empty_line()\n00745| --- NOTE: use longer code fence because lines could contain ```\n00746| output:add_line('`````' .. (language or ''))\n00747| output:add_lines(util.sanitize_lines(lines))\n00748| output:add_line('`````')\n00749| end\n00750| \n00751| ---@param output Output Output object to write to\n00752| ---@param code string\n00753| ---@param file_type string\n00754| function M._format_diff(output, code, file_type)\n00755| output:add_empty_line()\n00756| \n00757| --- NOTE: use longer code fence because code could contain ```\n00758| output:add_line('`````' .. file_type)\n00759| local lines = vim.split(code, '\\n')\n00760| if #lines > 5 then\n00761| lines = vim.list_slice(lines, 6)\n00762| end\n00763| \n00764| for _, line in ipairs(lines) do\n00765| local first_char = line:sub(1, 1)\n00766| if first_char == '+' or first_char == '-' then\n00767| local hl_group = first_char == '+' and 'OpencodeDiffAdd' or 'OpencodeDiffDelete'\n00768| output:add_line(' ' .. line:sub(2))\n00769| local line_idx = output:get_line_count()\n00770| output:add_extmark(line_idx - 1, function()\n00771| return {\n00772| end_col = 0,\n00773| end_row = line_idx,\n00774| virt_text = { { first_char, hl_group } },\n00775| hl_group = hl_group,\n00776| hl_eol = true,\n00777| priority = 5000,\n00778| right_gravity = true,\n00779| end_right_gravity = false,\n00780| virt_text_hide = false,\n00781| virt_text_pos = 'overlay',\n00782| virt_text_repeat_linebreak = false,\n00783| }\n00784| end)\n00785| else\n00786| output:add_line(line)\n00787| end\n00788| end\n00789| output:add_line('`````')\n00790| end\n00791| \n00792| ---@param output Output Output object to write to\n00793| ---@param start_line number\n00794| ---@param end_line number\n00795| ---@param hl_group string Highlight group for the border character\n00796| ---@param win_col number\n00797| ---@param text_hl_group? string Optional highlight group for the background/foreground of text lines\n00798| function M._add_vertical_border(output, start_line, end_line, hl_group, win_col, text_hl_group)\n00799| for line = start_line, end_line do\n00800| local extmark_opts = {\n00801| virt_text = { { require('opencode.ui.icons').get('border'), hl_group } },\n00802| virt_text_pos = 'overlay',\n00803| virt_text_win_col = win_col,\n00804| virt_text_repeat_linebreak = true,\n00805| }\n00806| \n00807| -- Add line highlight if text_hl_group is provided\n00808| if text_hl_group then\n00809| extmark_opts.line_hl_group = text_hl_group\n00810| end\n00811| \n00812| output:add_extmark(line - 1, extmark_opts --[[@as OutputExtmark]])\n00813| end\n00814| end\n00815| \n00816| ---Formats a single message part and returns the resulting output object\n00817| ---@param part OpencodeMessagePart The part to format\n00818| ---@param message? OpencodeMessage Optional message object to extract role and mentions from\n00819| ---@param is_last_part? boolean Whether this is the last part in the message, used to show an error if there is one\n00820| ---@return Output\n00821| function M.format_part(part, message, is_last_part)\n00822| local output = Output.new()\n00823| \n00824| if not message or not message.info or not message.info.role then\n00825| return output\n00826| end\n00827| \n00828| local content_added = false\n00829| local role = message.info.role\n00830| \n00831| if role == 'user' then\n00832| if part.type == 'text' and part.text then\n00833| if part.synthetic == true then\n00834| M._format_selection_context(output, part)\n00835| M._format_cursor_data_context(output, part)\n00836| M._format_diagnostics_context(output, part)\n00837| else\n00838| M._format_user_prompt(output, vim.trim(part.text), message)\n00839| content_added = true\n00840| end\n00841| elseif part.type == 'file' then\n00842| local file_line = M._format_context_file(output, part.filename)\n00843| if file_line then\n00844| M._add_vertical_border(output, file_line - 1, file_line, 'OpencodeMessageRoleUser', -3)\n00845| content_added = true\n00846| end\n00847| end\n00848| elseif role == 'assistant' then\n00849| if part.type == 'text' and part.text then\n00850| M._format_assistant_message(output, vim.trim(part.text))\n00851| content_added = true\n00852| elseif part.type == 'reasoning' and part.text then\n00853| M._format_reasoning(output, part)\n00854| content_added = true\n00855| elseif part.type == 'tool' then\n00856| M._format_tool(output, part)\n00857| content_added = true\n00858| elseif part.type == 'patch' and part.hash then\n00859| M._format_patch(output, part)\n00860| content_added = true\n00861| end\n00862| end\n00863| \n00864| if content_added then\n00865| output:add_empty_line()\n00866| end\n00867| \n00868| if is_last_part and role == 'assistant' and message.info.error and message.info.error ~= '' then\n00869| local error = message.info.error\n00870| local error_message = error.data and error.data.message or vim.inspect(error)\n00871| M._format_callout(output, 'ERROR', error_message)\n00872| output:add_empty_line()\n00873| end\n00874| \n00875| return output\n00876| end\n00877| \n00878| return M\n00879| \n\n(End of file - total 879 lines)\n",
+ "synthetic": true
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "file",
+ "url": "file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua",
+ "id": "prt_b8e7c60a7002ybV09VDHoQQeO7",
+ "filename": "lua/opencode/ui/formatter.lua",
+ "messageID": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "mime": "text/plain"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "id": "prt_b8e7c60a3002XHHlk77vAPApvR",
+ "messageID": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "text": "{\"content\":[{\"msg\":\"expected `SessionRevertInfo` but found `SessionRevertInfo?`.\",\"severity\":2,\"pos\":\"l156:c68\"},{\"msg\":\"expected `integer?` but found `number`.\",\"severity\":2,\"pos\":\"l490:c43\"},{\"msg\":\"expected `integer` but found `number`.\",\"severity\":2,\"pos\":\"l492:c45\"},{\"msg\":\"expected `integer?` but found `number`.\",\"severity\":2,\"pos\":\"l492:c62\"},{\"msg\":\"state.active_session may be nil\",\"severity\":2,\"pos\":\"l156:c68\"},{\"msg\":\"state.messages[#state.messages] may be nil\",\"severity\":2,\"pos\":\"l272:c74\"},{\"msg\":\"state.messages may be nil\",\"severity\":2,\"pos\":\"l272:c74\"},{\"msg\":\"Undefined field `[diag.severity]`.\",\"severity\":2,\"pos\":\"l435:c42\"},{\"msg\":\"Undefined field `command`.\",\"severity\":2,\"pos\":\"l526:c34\"},{\"msg\":\"Undefined field `command`.\",\"severity\":2,\"pos\":\"l527:c47\"},{\"msg\":\"Cannot assign `number` to `integer`.\",\"severity\":2,\"pos\":\"l493:c5\"}],\"context_type\":\"diagnostics\"}",
+ "synthetic": true
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "title": "New session - 2026-01-05T14:07:52.149Z",
+ "version": "1.1.2",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "time": { "updated": 1767622074603, "created": 1767622072149 }
+ }
+ },
+ "type": "session.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "info": {
+ "providerID": "github-copilot",
+ "role": "assistant",
+ "path": {
+ "root": "/home/francis/Projects/_nvim/opencode.nvim",
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "agent": "build",
+ "time": { "created": 1767622074609 },
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "mode": "build",
+ "modelID": "gpt-4.1",
+ "id": "msg_b8e7c60f1001aEWYlAaDRXQ4aJ",
+ "parentID": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "cost": 0,
+ "tokens": { "output": 0, "reasoning": 0, "input": 0, "cache": { "write": 0, "read": 0 } }
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "time": { "created": 1767622074530 },
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "role": "user",
+ "id": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "agent": "build",
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "summary": { "diffs": [] }
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "title": "New session - 2026-01-05T14:07:52.149Z",
+ "version": "1.1.2",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "time": { "updated": 1767622074670, "created": 1767622072149 },
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "summary": { "deletions": 0, "additions": 0, "files": 0 }
+ }
+ },
+ "type": "session.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "step-start",
+ "id": "prt_b8e7c6672001F10WAiQKbzNEtE",
+ "snapshot": "5ba6e95774829e7f501299039b72b72dc32c6620",
+ "messageID": "msg_b8e7c60f1001aEWYlAaDRXQ4aJ"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "tool",
+ "messageID": "msg_b8e7c60f1001aEWYlAaDRXQ4aJ",
+ "id": "prt_b8e7c6686001cCV44vsFtbpF42",
+ "state": { "status": "pending", "input": {}, "raw": "" },
+ "callID": "call_KAC0LdAxKEbU6HTAPH5QJfGx",
+ "tool": "bash"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "tool",
+ "messageID": "msg_b8e7c60f1001aEWYlAaDRXQ4aJ",
+ "id": "prt_b8e7c6686001cCV44vsFtbpF42",
+ "state": {
+ "status": "running",
+ "input": { "description": "Shows working tree status", "command": "git status" },
+ "time": { "start": 1767622076189 }
+ },
+ "callID": "call_KAC0LdAxKEbU6HTAPH5QJfGx",
+ "tool": "bash"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "tool": { "messageID": "msg_b8e7c60f1001aEWYlAaDRXQ4aJ", "callID": "call_KAC0LdAxKEbU6HTAPH5QJfGx" },
+ "patterns": ["git status"],
+ "id": "per_b8e7c6744001DX6EZ9KHM15RLi",
+ "permission": "bash",
+ "always": ["git status*"],
+ "metadata": {}
+ },
+ "type": "permission.asked"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "time": { "created": 1767622074530 },
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "role": "user",
+ "id": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "agent": "build",
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "summary": { "title": "Running git status to list changed files", "diffs": [] }
+ }
+ },
+ "type": "message.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "info": {
+ "title": "Running git status for formatter.lua changes",
+ "version": "1.1.2",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "time": { "updated": 1767622082619, "created": 1767622072149 },
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "summary": { "deletions": 0, "additions": 0, "files": 0 }
+ }
+ },
+ "type": "session.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "requestID": "per_b8e7c6744001DX6EZ9KHM15RLi",
+ "reply": "once"
+ },
+ "type": "permission.replied"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "tool",
+ "messageID": "msg_b8e7c60f1001aEWYlAaDRXQ4aJ",
+ "id": "prt_b8e7c6686001cCV44vsFtbpF42",
+ "state": {
+ "title": "Shows working tree status",
+ "input": { "description": "Shows working tree status", "command": "git status" },
+ "output": "On branch main\nYour branch is up to date with 'origin/main'.\n\nChanges not staged for commit:\n (use \"git add ...\" to update what will be committed)\n (use \"git restore ...\" to discard changes in working directory)\n\tmodified: lua/opencode/event_manager.lua\n\tmodified: lua/opencode/ui/formatter.lua\n\tmodified: lua/opencode/ui/renderer.lua\n\nUntracked files:\n (use \"git add ...\" to include in what will be committed)\n\ttest.lua\n\ttests/data/permission_ask_new.json\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n",
+ "status": "completed",
+ "metadata": {
+ "exit": 0,
+ "description": "Shows working tree status",
+ "output": "On branch main\nYour branch is up to date with 'origin/main'.\n\nChanges not staged for commit:\n (use \"git add ...\" to update what will be committed)\n (use \"git restore ...\" to discard changes in working directory)\n\tmodified: lua/opencode/event_manager.lua\n\tmodified: lua/opencode/ui/formatter.lua\n\tmodified: lua/opencode/ui/renderer.lua\n\nUntracked files:\n (use \"git add ...\" to include in what will be committed)\n\ttest.lua\n\ttests/data/permission_ask_new.json\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
+ },
+ "time": { "start": 1767622076189, "end": 1767622106719 }
+ },
+ "callID": "call_KAC0LdAxKEbU6HTAPH5QJfGx",
+ "tool": "bash"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "step-finish",
+ "messageID": "msg_b8e7c60f1001aEWYlAaDRXQ4aJ",
+ "id": "prt_b8e7cde62001EgRfgQpjNPuSc8",
+ "reason": "tool-calls",
+ "cost": 0,
+ "snapshot": "34a4eef77f714f2e3a282c410dbda315c4781fee",
+ "tokens": { "output": 23, "reasoning": 0, "input": 10887, "cache": { "write": 0, "read": 9984 } }
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "providerID": "github-copilot",
+ "role": "assistant",
+ "path": {
+ "root": "/home/francis/Projects/_nvim/opencode.nvim",
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "agent": "build",
+ "finish": "tool-calls",
+ "time": { "created": 1767622074609 },
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "mode": "build",
+ "modelID": "gpt-4.1",
+ "id": "msg_b8e7c60f1001aEWYlAaDRXQ4aJ",
+ "parentID": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "cost": 0,
+ "tokens": { "output": 23, "reasoning": 0, "input": 10887, "cache": { "write": 0, "read": 9984 } }
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "patch",
+ "id": "prt_b8e7cde8f001JcNpZEALOVaZnq",
+ "hash": "5ba6e95774829e7f501299039b72b72dc32c6620",
+ "messageID": "msg_b8e7c60f1001aEWYlAaDRXQ4aJ",
+ "files": ["/home/francis/Projects/_nvim/opencode.nvim/tests/data/permission_ask_new.json"]
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "providerID": "github-copilot",
+ "role": "assistant",
+ "path": {
+ "root": "/home/francis/Projects/_nvim/opencode.nvim",
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "agent": "build",
+ "finish": "tool-calls",
+ "time": { "created": 1767622074609, "completed": 1767622106776 },
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "mode": "build",
+ "modelID": "gpt-4.1",
+ "id": "msg_b8e7c60f1001aEWYlAaDRXQ4aJ",
+ "parentID": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "cost": 0,
+ "tokens": { "output": 23, "reasoning": 0, "input": 10887, "cache": { "write": 0, "read": 9984 } }
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "providerID": "github-copilot",
+ "role": "assistant",
+ "path": {
+ "root": "/home/francis/Projects/_nvim/opencode.nvim",
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "agent": "build",
+ "time": { "created": 1767622106782 },
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "mode": "build",
+ "modelID": "gpt-4.1",
+ "id": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "parentID": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "cost": 0,
+ "tokens": { "output": 0, "reasoning": 0, "input": 0, "cache": { "write": 0, "read": 0 } }
+ }
+ },
+ "type": "message.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "time": { "created": 1767622074530 },
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "role": "user",
+ "id": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "agent": "build",
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "summary": {
+ "title": "Running git status to list changed files",
+ "diffs": [
+ {
+ "file": "tests/data/permission_ask_new.json",
+ "after": "[{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"time\":{\"updated\":1767622072149,\"created\":1767622072149}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"time\":{\"created\":1767622074530}}},\"type\":\"message.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3001M2zsH9REfPdlQt\",\"text\":\"@no-trust run a git status and tell me what files are changed\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3003Ta9NcXkN0lb0lF\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"Called the Read tool with the following input: {\\\"filePath\\\":\\\"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\\\"}\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a7001d3WhKOu2vCR4Cf\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"\\n00001| local context_module = require('opencode.context')\\n00002| local icons = require('opencode.ui.icons')\\n00003| local util = require('opencode.util')\\n00004| local Output = require('opencode.ui.output')\\n00005| local state = require('opencode.state')\\n00006| local config = require('opencode.config')\\n00007| local snapshot = require('opencode.snapshot')\\n00008| local mention = require('opencode.ui.mention')\\n00009| \\n00010| local M = {}\\n00011| \\n00012| M.separator = {\\n00013| '----',\\n00014| '',\\n00015| }\\n00016| \\n00017| ---@param output Output\\n00018| ---@param part OpencodeMessagePart\\n00019| function M._format_reasoning(output, part)\\n00020| local text = vim.trim(part.text or '')\\n00021| if text == '' then\\n00022| return\\n00023| end\\n00024| \\n00025| local start_line = output:get_line_count() + 1\\n00026| \\n00027| local title = 'Reasoning'\\n00028| local time = part.time\\n00029| if time and type(time) == 'table' and time.start then\\n00030| local start_text = util.format_time(time.start) or ''\\n00031| local end_text = (time['end'] and util.format_time(time['end'])) or nil\\n00032| if end_text and end_text ~= '' then\\n00033| title = string.format('%s (%s - %s)', title, start_text, end_text)\\n00034| elseif start_text ~= '' then\\n00035| title = string.format('%s (%s)', title, start_text)\\n00036| end\\n00037| end\\n00038| \\n00039| M._format_action(output, icons.get('reasoning') .. ' ' .. title, '')\\n00040| \\n00041| if config.ui.output.tools.show_reasoning_output then\\n00042| output:add_empty_line()\\n00043| output:add_lines(vim.split(text, '\\\\n'))\\n00044| output:add_empty_line()\\n00045| end\\n00046| \\n00047| local end_line = output:get_line_count()\\n00048| if end_line - start_line > 1 then\\n00049| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1, 'OpencodeReasoningText')\\n00050| else\\n00051| output:add_extmark(start_line - 1, {\\n00052| line_hl_group = 'OpencodeReasoningText',\\n00053| } --[[@as OutputExtmark]])\\n00054| end\\n00055| end\\n00056| \\n00057| function M._handle_permission_request(output, part)\\n00058| if part.state and part.state.status == 'error' and part.state.error then\\n00059| if part.state.error:match('rejected permission') then\\n00060| state.current_permission = nil\\n00061| else\\n00062| vim.notify('Unknown part state error: ' .. part.state.error)\\n00063| end\\n00064| return\\n00065| end\\n00066| \\n00067| M._format_permission_request(output)\\n00068| end\\n00069| \\n00070| function M._format_permission_request(output)\\n00071| local keys\\n00072| \\n00073| if require('opencode.ui.ui').is_opencode_focused() then\\n00074| keys = {\\n00075| config.keymap.permission.accept,\\n00076| config.keymap.permission.accept_all,\\n00077| config.keymap.permission.deny,\\n00078| }\\n00079| else\\n00080| keys = {\\n00081| config.get_key_for_function('editor', 'permission_accept'),\\n00082| config.get_key_for_function('editor', 'permission_accept_all'),\\n00083| config.get_key_for_function('editor', 'permission_deny'),\\n00084| }\\n00085| end\\n00086| \\n00087| output:add_empty_line()\\n00088| output:add_line('> [!WARNING] Permission required to run this tool.')\\n00089| output:add_line('>')\\n00090| output:add_line(('> Accept `%s` Always `%s` Deny `%s`'):format(unpack(keys)))\\n00091| output:add_empty_line()\\n00092| end\\n00093| \\n00094| ---Calculate statistics for reverted messages and tool calls\\n00095| ---@param messages {info: MessageInfo, parts: OpencodeMessagePart[]}[] All messages in the session\\n00096| ---@param revert_index number Index of the message where revert occurred\\n00097| ---@param revert_info SessionRevertInfo Revert information\\n00098| ---@return {messages: number, tool_calls: number, files: table}\\n00099| function M._calculate_revert_stats(messages, revert_index, revert_info)\\n00100| local stats = {\\n00101| messages = 0,\\n00102| tool_calls = 0,\\n00103| files = {}, -- { [filename] = { additions = n, deletions = m } }\\n00104| }\\n00105| \\n00106| for i = revert_index, #messages do\\n00107| local msg = messages[i]\\n00108| if msg.info.role == 'user' then\\n00109| stats.messages = stats.messages + 1\\n00110| end\\n00111| if msg.parts then\\n00112| for _, part in ipairs(msg.parts) do\\n00113| if part.type == 'tool' then\\n00114| stats.tool_calls = stats.tool_calls + 1\\n00115| end\\n00116| end\\n00117| end\\n00118| end\\n00119| \\n00120| if revert_info.diff then\\n00121| local current_file = nil\\n00122| for line in revert_info.diff:gmatch('[^\\\\r\\\\n]+') do\\n00123| local file_a = line:match('^%-%-%- ([ab]/.+)')\\n00124| local file_b = line:match('^%+%+%+ ([ab]/.+)')\\n00125| if file_b then\\n00126| current_file = file_b:gsub('^[ab]/', '')\\n00127| if not stats.files[current_file] then\\n00128| stats.files[current_file] = { additions = 0, deletions = 0 }\\n00129| end\\n00130| elseif file_a then\\n00131| current_file = file_a:gsub('^[ab]/', '')\\n00132| if not stats.files[current_file] then\\n00133| stats.files[current_file] = { additions = 0, deletions = 0 }\\n00134| end\\n00135| elseif line:sub(1, 1) == '+' and not line:match('^%+%+%+') then\\n00136| if current_file then\\n00137| stats.files[current_file].additions = stats.files[current_file].additions + 1\\n00138| end\\n00139| elseif line:sub(1, 1) == '-' and not line:match('^%-%-%-') then\\n00140| if current_file then\\n00141| stats.files[current_file].deletions = stats.files[current_file].deletions + 1\\n00142| end\\n00143| end\\n00144| end\\n00145| end\\n00146| \\n00147| return stats\\n00148| end\\n00149| \\n00150| ---Format the revert callout with statistics\\n00151| ---@param session_data OpencodeMessage[] All messages in the session\\n00152| ---@param start_idx number Index of the message where revert occurred\\n00153| ---@return Output output object representing the lines, extmarks, and actions\\n00154| function M._format_revert_message(session_data, start_idx)\\n00155| local output = Output.new()\\n00156| local stats = M._calculate_revert_stats(session_data, start_idx, state.active_session.revert)\\n00157| local message_text = stats.messages == 1 and 'message' or 'messages'\\n00158| local tool_text = stats.tool_calls == 1 and 'tool call' or 'tool calls'\\n00159| \\n00160| output:add_lines(M.separator)\\n00161| output:add_line(\\n00162| string.format('> %d %s reverted, %d %s reverted', stats.messages, message_text, stats.tool_calls, tool_text)\\n00163| )\\n00164| output:add_line('>')\\n00165| output:add_line('> type `/redo` to restore.')\\n00166| output:add_empty_line()\\n00167| \\n00168| if stats.files and next(stats.files) then\\n00169| for file, fstats in pairs(stats.files) do\\n00170| local file_diff = {}\\n00171| if fstats.additions > 0 then\\n00172| table.insert(file_diff, '+' .. fstats.additions)\\n00173| end\\n00174| if fstats.deletions > 0 then\\n00175| table.insert(file_diff, '-' .. fstats.deletions)\\n00176| end\\n00177| if #file_diff > 0 then\\n00178| local line_str = string.format(icons.get('file') .. '%s: %s', file, table.concat(file_diff, ' '))\\n00179| local line_idx = output:add_line(line_str)\\n00180| local col = #(' ' .. file .. ': ')\\n00181| for _, diff in ipairs(file_diff) do\\n00182| local hl_group = diff:sub(1, 1) == '+' and 'OpencodeDiffAddText' or 'OpencodeDiffDeleteText'\\n00183| output:add_extmark(line_idx - 1, {\\n00184| virt_text = { { diff, hl_group } },\\n00185| virt_text_pos = 'inline',\\n00186| virt_text_win_col = col,\\n00187| priority = 1000,\\n00188| } --[[@as OutputExtmark]])\\n00189| col = col + #diff + 1\\n00190| end\\n00191| end\\n00192| end\\n00193| end\\n00194| return output\\n00195| end\\n00196| \\n00197| local function add_action(output, text, action_type, args, key, line)\\n00198| -- actions use api-indexing (e.g. 0 indexed)\\n00199| line = (line or output:get_line_count()) - 1\\n00200| output:add_action({\\n00201| text = text,\\n00202| type = action_type,\\n00203| args = args,\\n00204| key = key,\\n00205| display_line = line,\\n00206| range = { from = line, to = line },\\n00207| })\\n00208| end\\n00209| \\n00210| ---@param output Output Output object to write to\\n00211| ---@param part OpencodeMessagePart\\n00212| function M._format_patch(output, part)\\n00213| if not part.hash then\\n00214| return\\n00215| end\\n00216| \\n00217| local restore_points = snapshot.get_restore_points_by_parent(part.hash) or {}\\n00218| M._format_action(output, icons.get('snapshot') .. ' Created Snapshot', vim.trim(part.hash:sub(1, 8)))\\n00219| \\n00220| -- Anchor all snapshot-level actions to the snapshot header line\\n00221| add_action(output, '[R]evert file', 'diff_revert_selected_file', { part.hash }, 'R')\\n00222| add_action(output, 'Revert [A]ll', 'diff_revert_all', { part.hash }, 'A')\\n00223| add_action(output, '[D]iff', 'diff_open', { part.hash }, 'D')\\n00224| \\n00225| if #restore_points > 0 then\\n00226| for _, restore_point in ipairs(restore_points) do\\n00227| output:add_line(\\n00228| string.format(\\n00229| ' %s Restore point `%s` - %s ',\\n00230| icons.get('restore_point'),\\n00231| vim.trim(restore_point.id:sub(1, 8)),\\n00232| util.format_time(restore_point.created_at)\\n00233| )\\n00234| )\\n00235| add_action(output, 'Restore [A]ll', 'diff_restore_snapshot_all', { restore_point.id }, 'A')\\n00236| add_action(output, '[R]estore file', 'diff_restore_snapshot_file', { restore_point.id }, 'R')\\n00237| end\\n00238| end\\n00239| end\\n00240| \\n00241| ---@param output Output Output object to write to\\n00242| ---@param message MessageInfo\\n00243| function M._format_error(output, message)\\n00244| output:add_empty_line()\\n00245| M._format_callout(output, 'ERROR', vim.inspect(message.error))\\n00246| end\\n00247| \\n00248| ---@param message OpencodeMessage\\n00249| ---@return Output\\n00250| function M.format_message_header(message)\\n00251| local output = Output.new()\\n00252| \\n00253| output:add_lines(M.separator)\\n00254| local role = message.info.role or 'unknown'\\n00255| local icon = message.info.role == 'user' and icons.get('header_user') or icons.get('header_assistant')\\n00256| \\n00257| local time = message.info.time and message.info.time.created or nil\\n00258| local time_text = (time and ' (' .. util.format_time(time) .. ')' or '')\\n00259| local role_hl = 'OpencodeMessageRole' .. role:sub(1, 1):upper() .. role:sub(2)\\n00260| local model_text = message.info.modelID and ' ' .. message.info.modelID or ''\\n00261| \\n00262| local debug_text = config.debug.show_ids and ' [' .. message.info.id .. ']' or ''\\n00263| \\n00264| local display_name\\n00265| if role == 'assistant' then\\n00266| local mode = message.info.mode\\n00267| if mode and mode ~= '' then\\n00268| display_name = mode:upper()\\n00269| else\\n00270| -- For the most recent assistant message, show current_mode if mode is missing\\n00271| -- This handles new messages that haven't been stamped yet\\n00272| local is_last_message = #state.messages == 0 or message.info.id == state.messages[#state.messages].info.id\\n00273| if is_last_message and state.current_mode and state.current_mode ~= '' then\\n00274| display_name = state.current_mode:upper()\\n00275| else\\n00276| display_name = 'ASSISTANT'\\n00277| end\\n00278| end\\n00279| else\\n00280| display_name = role:upper()\\n00281| end\\n00282| \\n00283| output:add_extmark(output:get_line_count() - 1, {\\n00284| virt_text = {\\n00285| { icon, role_hl },\\n00286| { ' ' },\\n00287| { display_name, role_hl },\\n00288| { model_text, 'OpencodeHint' },\\n00289| { time_text, 'OpencodeHint' },\\n00290| { debug_text, 'OpencodeHint' },\\n00291| },\\n00292| virt_text_win_col = -3,\\n00293| priority = 10,\\n00294| } --[[@as OutputExtmark]])\\n00295| \\n00296| -- Only want to show the error if we have no parts. If we have parts, they'll\\n00297| -- handle rendering the error\\n00298| if\\n00299| role == 'assistant'\\n00300| and message.info.error\\n00301| and message.info.error ~= ''\\n00302| and (not message.parts or #message.parts == 0)\\n00303| then\\n00304| local error = message.info.error\\n00305| local error_message = error.data and error.data.message or vim.inspect(error)\\n00306| \\n00307| output:add_line('')\\n00308| M._format_callout(output, 'ERROR', error_message)\\n00309| end\\n00310| \\n00311| output:add_line('')\\n00312| return output\\n00313| end\\n00314| \\n00315| ---@param output Output Output object to write to\\n00316| ---@param callout string Callout type (e.g., 'ERROR', 'TODO')\\n00317| ---@param text string Callout text content\\n00318| ---@param title? string Optional title for the callout\\n00319| function M._format_callout(output, callout, text, title)\\n00320| title = title and title .. ' ' or ''\\n00321| local win_width = (state.windows and state.windows.output_win and vim.api.nvim_win_is_valid(state.windows.output_win))\\n00322| and vim.api.nvim_win_get_width(state.windows.output_win)\\n00323| or config.ui.window_width\\n00324| or 80\\n00325| if #text > win_width - 4 then\\n00326| local ok, substituted = pcall(vim.fn.substitute, text, '\\\\v(.{' .. (win_width - 8) .. '})', '\\\\1\\\\n', 'g')\\n00327| text = ok and substituted or text\\n00328| end\\n00329| \\n00330| -- Trim off any trailing newlines so there isn't an extra line in the\\n00331| -- extmarks section\\n00332| local lines = vim.split(text:gsub('\\\\n$', ''), '\\\\n')\\n00333| if #lines == 1 and title == '' then\\n00334| output:add_line('> [!' .. callout .. '] ' .. lines[1])\\n00335| else\\n00336| output:add_line('> [!' .. callout .. ']' .. title)\\n00337| output:add_line('>')\\n00338| output:add_lines(lines, '> ')\\n00339| end\\n00340| end\\n00341| \\n00342| ---@param output Output Output object to write to\\n00343| ---@param text string\\n00344| ---@param message? OpencodeMessage Optional message object to extract mentions from\\n00345| function M._format_user_prompt(output, text, message)\\n00346| local start_line = output:get_line_count()\\n00347| \\n00348| output:add_lines(vim.split(text, '\\\\n'))\\n00349| \\n00350| local end_line = output:get_line_count()\\n00351| \\n00352| local end_line_extmark_offset = 0\\n00353| \\n00354| local mentions = {}\\n00355| if message and message.parts then\\n00356| -- message.parts will only be filled out on a re-render\\n00357| -- we need to collect the mentions here\\n00358| for _, part in ipairs(message.parts) do\\n00359| if part.type == 'file' then\\n00360| -- we're rerendering this part and we have files, the space after the user prompt\\n00361| -- also needs an extmark\\n00362| end_line_extmark_offset = 1\\n00363| if part.source and part.source.text then\\n00364| table.insert(mentions, part.source.text)\\n00365| end\\n00366| elseif part.type == 'agent' then\\n00367| if part.source then\\n00368| table.insert(mentions, part.source)\\n00369| end\\n00370| end\\n00371| end\\n00372| end\\n00373| \\n00374| if #mentions > 0 then\\n00375| mention.highlight_mentions_in_output(output, text, mentions, start_line)\\n00376| end\\n00377| \\n00378| M._add_vertical_border(output, start_line, end_line + end_line_extmark_offset, 'OpencodeMessageRoleUser', -3)\\n00379| end\\n00380| \\n00381| ---@param output Output Output object to write to\\n00382| ---@param part OpencodeMessagePart\\n00383| function M._format_selection_context(output, part)\\n00384| local json = context_module.decode_json_context(part.text or '', 'selection')\\n00385| if not json then\\n00386| return\\n00387| end\\n00388| local start_line = output:get_line_count()\\n00389| output:add_lines(vim.split(json.content or '', '\\\\n'))\\n00390| output:add_empty_line()\\n00391| \\n00392| local end_line = output:get_line_count()\\n00393| \\n00394| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00395| end\\n00396| \\n00397| ---@param output Output Output object to write to\\n00398| ---@param part OpencodeMessagePart\\n00399| function M._format_cursor_data_context(output, part)\\n00400| local json = context_module.decode_json_context(part.text or '', 'cursor-data')\\n00401| if not json then\\n00402| return\\n00403| end\\n00404| local start_line = output:get_line_count()\\n00405| output:add_line('Line ' .. json.line .. ':')\\n00406| output:add_lines(vim.split(json.line_content or '', '\\\\n'))\\n00407| output:add_empty_line()\\n00408| \\n00409| local end_line = output:get_line_count()\\n00410| \\n00411| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00412| end\\n00413| \\n00414| ---@param output Output Output object to write to\\n00415| ---@param part OpencodeMessagePart\\n00416| function M._format_diagnostics_context(output, part)\\n00417| local json = context_module.decode_json_context(part.text or '', 'diagnostics')\\n00418| if not json then\\n00419| return\\n00420| end\\n00421| local start_line = output:get_line_count()\\n00422| local diagnostics = json.content --[[@as OpencodeDiagnostic[] ]]\\n00423| if not diagnostics or type(diagnostics) ~= 'table' or #diagnostics == 0 then\\n00424| return\\n00425| end\\n00426| \\n00427| local diagnostics_count = { error = 0, warn = 0, info = 0 }\\n00428| local diagnostics_icons = {\\n00429| error = icons.get('error'),\\n00430| warn = icons.get('warning'),\\n00431| info = icons.get('info'),\\n00432| }\\n00433| \\n00434| for _, diag in ipairs(diagnostics) do\\n00435| local name = vim.diagnostic.severity[diag.severity]:lower()\\n00436| diagnostics_count[name] = diagnostics_count[name] + 1\\n00437| end\\n00438| \\n00439| local diag_line = '**Diagnostics:**'\\n00440| for name, count in pairs(diagnostics_count) do\\n00441| if count > 0 then\\n00442| diag_line = diag_line .. (string.format(' %s(%d)', diagnostics_icons[name], count))\\n00443| end\\n00444| end\\n00445| output:add_line(diag_line)\\n00446| output:add_empty_line()\\n00447| local end_line = output:get_line_count()\\n00448| \\n00449| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00450| end\\n00451| \\n00452| ---Format and display the file path in the context\\n00453| ---@param output Output Output object to write to\\n00454| ---@param path string|nil File path\\n00455| function M._format_context_file(output, path)\\n00456| if not path or path == '' then\\n00457| return\\n00458| end\\n00459| local cwd = vim.fn.getcwd()\\n00460| if vim.startswith(path, cwd) then\\n00461| path = path:sub(#cwd + 2)\\n00462| end\\n00463| return output:add_line(string.format('[%s](%s)', path, path))\\n00464| end\\n00465| \\n00466| ---@param output Output Output object to write to\\n00467| ---@param text string\\n00468| function M._format_assistant_message(output, text)\\n00469| local reference_picker = require('opencode.ui.reference_picker')\\n00470| local references = reference_picker.parse_references(text, '')\\n00471| \\n00472| -- If no references, just add the text as-is\\n00473| if #references == 0 then\\n00474| output:add_lines(vim.split(text, '\\\\n'))\\n00475| return\\n00476| end\\n00477| \\n00478| -- Sort references by match_start position (ascending)\\n00479| table.sort(references, function(a, b)\\n00480| return a.match_start < b.match_start\\n00481| end)\\n00482| \\n00483| -- Build a new text with icons inserted before each reference\\n00484| local result = ''\\n00485| local last_pos = 1\\n00486| local ref_icon = icons.get('reference')\\n00487| \\n00488| for _, ref in ipairs(references) do\\n00489| -- Add text before this reference\\n00490| result = result .. text:sub(last_pos, ref.match_start - 1)\\n00491| -- Add the icon and the reference\\n00492| result = result .. ref_icon .. text:sub(ref.match_start, ref.match_end)\\n00493| last_pos = ref.match_end + 1\\n00494| end\\n00495| \\n00496| -- Add any remaining text after the last reference\\n00497| if last_pos <= #text then\\n00498| result = result .. text:sub(last_pos)\\n00499| end\\n00500| \\n00501| output:add_lines(vim.split(result, '\\\\n'))\\n00502| end\\n00503| \\n00504| ---@param output Output Output object to write to\\n00505| ---@param tool_type string Tool type (e.g., 'run', 'read', 'edit', etc.)\\n00506| ---@param value string Value associated with the action (e.g., filename, command)\\n00507| function M._format_action(output, tool_type, value)\\n00508| if not tool_type or not value then\\n00509| return\\n00510| end\\n00511| local line = string.format('**%s** %s', tool_type, value and #value > 0 and ('`' .. value .. '`') or '')\\n00512| \\n00513| output:add_line(line)\\n00514| end\\n00515| \\n00516| ---@param output Output Output object to write to\\n00517| ---@param input BashToolInput data for the tool\\n00518| ---@param metadata BashToolMetadata Metadata for the tool use\\n00519| function M._format_bash_tool(output, input, metadata)\\n00520| M._format_action(output, icons.get('run') .. ' run', input and input.description)\\n00521| \\n00522| if not config.ui.output.tools.show_output then\\n00523| return\\n00524| end\\n00525| \\n00526| if metadata.output or metadata.command or input.command then\\n00527| local command = input.command or metadata.command or ''\\n00528| local command_output = metadata.output and metadata.output ~= '' and ('\\\\n' .. metadata.output) or ''\\n00529| M._format_code(output, vim.split('> ' .. command .. '\\\\n' .. command_output, '\\\\n'), 'bash')\\n00530| end\\n00531| end\\n00532| \\n00533| ---@param output Output Output object to write to\\n00534| ---@param tool_type string Tool type (e.g., 'read', 'edit', 'write')\\n00535| ---@param input FileToolInput data for the tool\\n00536| ---@param metadata FileToolMetadata Metadata for the tool use\\n00537| function M._format_file_tool(output, tool_type, input, metadata)\\n00538| local file_name = input and vim.fn.fnamemodify(input.filePath, ':t') or ''\\n00539| local file_type = input and util.get_markdown_filetype(input.filePath) or ''\\n00540| local tool_action_icons = { read = icons.get('read'), edit = icons.get('edit'), write = icons.get('write') }\\n00541| \\n00542| M._format_action(output, tool_action_icons[tool_type] .. ' ' .. tool_type, file_name)\\n00543| \\n00544| if not config.ui.output.tools.show_output then\\n00545| return\\n00546| end\\n00547| \\n00548| if tool_type == 'edit' and metadata.diff then\\n00549| M._format_diff(output, metadata.diff, file_type)\\n00550| elseif tool_type == 'write' and input and input.content then\\n00551| M._format_code(output, vim.split(input.content, '\\\\n'), file_type)\\n00552| end\\n00553| end\\n00554| \\n00555| ---@param output Output Output object to write to\\n00556| ---@param title string\\n00557| ---@param input TodoToolInput\\n00558| function M._format_todo_tool(output, title, input)\\n00559| M._format_action(output, icons.get('plan') .. ' plan', (title or ''))\\n00560| if not config.ui.output.tools.show_output then\\n00561| return\\n00562| end\\n00563| \\n00564| local todos = input and input.todos or {}\\n00565| \\n00566| for _, item in ipairs(todos) do\\n00567| local statuses = { in_progress = '-', completed = 'x', pending = ' ' }\\n00568| output:add_line(string.format('- [%s] %s ', statuses[item.status], item.content))\\n00569| end\\n00570| end\\n00571| \\n00572| ---@param output Output Output object to write to\\n00573| ---@param input GlobToolInput data for the tool\\n00574| ---@param metadata GlobToolMetadata Metadata for the tool use\\n00575| function M._format_glob_tool(output, input, metadata)\\n00576| M._format_action(output, icons.get('search') .. ' glob', input and input.pattern)\\n00577| if not config.ui.output.tools.show_output then\\n00578| return\\n00579| end\\n00580| local prefix = metadata.truncated and ' more than' or ''\\n00581| output:add_line(string.format('Found%s `%d` file(s):', prefix, metadata.count or 0))\\n00582| end\\n00583| \\n00584| ---@param output Output Output object to write to\\n00585| ---@param input GrepToolInput data for the tool\\n00586| ---@param metadata GrepToolMetadata Metadata for the tool use\\n00587| function M._format_grep_tool(output, input, metadata)\\n00588| input = input or { path = '', include = '', pattern = '' }\\n00589| \\n00590| local grep_str = string.format('%s` `%s', (input.path or input.include) or '', input.pattern or '')\\n00591| \\n00592| M._format_action(output, icons.get('search') .. ' grep', grep_str)\\n00593| if not config.ui.output.tools.show_output then\\n00594| return\\n00595| end\\n00596| local prefix = metadata.truncated and ' more than' or ''\\n00597| output:add_line(\\n00598| string.format('Found%s `%d` match' .. (metadata.matches ~= 1 and 'es' or ''), prefix, metadata.matches or 0)\\n00599| )\\n00600| end\\n00601| \\n00602| ---@param output Output Output object to write to\\n00603| ---@param input WebFetchToolInput data for the tool\\n00604| function M._format_webfetch_tool(output, input)\\n00605| M._format_action(output, icons.get('web') .. ' fetch', input and input.url)\\n00606| end\\n00607| \\n00608| ---@param output Output Output object to write to\\n00609| ---@param input ListToolInput\\n00610| ---@param metadata ListToolMetadata\\n00611| ---@param tool_output string\\n00612| function M._format_list_tool(output, input, metadata, tool_output)\\n00613| M._format_action(output, icons.get('list') .. ' list', input and input.path or '')\\n00614| if not config.ui.output.tools.show_output then\\n00615| return\\n00616| end\\n00617| local lines = vim.split(vim.trim(tool_output or ''), '\\\\n')\\n00618| if #lines < 1 or metadata.count == 0 then\\n00619| output:add_line('No files found.')\\n00620| return\\n00621| end\\n00622| if #lines > 1 then\\n00623| output:add_line('Files:')\\n00624| for i = 2, #lines do\\n00625| local file = vim.trim(lines[i])\\n00626| if file ~= '' then\\n00627| output:add_line(' • ' .. file)\\n00628| end\\n00629| end\\n00630| end\\n00631| if metadata.truncated then\\n00632| output:add_line(string.format('Results truncated, showing first %d files', metadata.count or '?'))\\n00633| end\\n00634| end\\n00635| \\n00636| ---@param output Output Output object to write to\\n00637| ---@param part OpencodeMessagePart\\n00638| function M._format_tool(output, part)\\n00639| local tool = part.tool\\n00640| if not tool or not part.state then\\n00641| return\\n00642| end\\n00643| \\n00644| local start_line = output:get_line_count() + 1\\n00645| local input = part.state.input or {}\\n00646| local metadata = part.state.metadata or {}\\n00647| local tool_output = part.state.output or ''\\n00648| \\n00649| if state.current_permission and state.current_permission.messageID == part.messageID then\\n00650| metadata = state.current_permission.metadata or metadata\\n00651| end\\n00652| \\n00653| if tool == 'bash' then\\n00654| M._format_bash_tool(output, input --[[@as BashToolInput]], metadata --[[@as BashToolMetadata]])\\n00655| elseif tool == 'read' or tool == 'edit' or tool == 'write' then\\n00656| M._format_file_tool(output, tool, input --[[@as FileToolInput]], metadata --[[@as FileToolMetadata]])\\n00657| elseif tool == 'todowrite' then\\n00658| M._format_todo_tool(output, part.state.title, input --[[@as TodoToolInput]])\\n00659| elseif tool == 'glob' then\\n00660| M._format_glob_tool(output, input --[[@as GlobToolInput]], metadata --[[@as GlobToolMetadata]])\\n00661| elseif tool == 'list' then\\n00662| M._format_list_tool(output, input --[[@as ListToolInput]], metadata --[[@as ListToolMetadata]], tool_output)\\n00663| elseif tool == 'grep' then\\n00664| M._format_grep_tool(output, input --[[@as GrepToolInput]], metadata --[[@as GrepToolMetadata]])\\n00665| elseif tool == 'webfetch' then\\n00666| M._format_webfetch_tool(output, input --[[@as WebFetchToolInput]])\\n00667| elseif tool == 'task' then\\n00668| M._format_task_tool(output, input --[[@as TaskToolInput]], metadata --[[@as TaskToolMetadata]], tool_output)\\n00669| else\\n00670| M._format_action(output, icons.get('tool') .. ' tool', tool)\\n00671| end\\n00672| \\n00673| if part.state.status == 'error' and part.state.error then\\n00674| output:add_line('')\\n00675| M._format_callout(output, 'ERROR', part.state.error)\\n00676| ---@diagnostic disable-next-line: undefined-field\\n00677| elseif part.state.input and part.state.input.error then\\n00678| output:add_line('')\\n00679| ---I'm not sure about the type with state.input.error\\n00680| ---@diagnostic disable-next-line: undefined-field\\n00681| M._format_callout(output, 'ERROR', part.state.input.error)\\n00682| end\\n00683| \\n00684| if\\n00685| state.current_permission\\n00686| and (\\n00687| (\\n00688| state.current_permission.tool\\n00689| and state.current_permission.tool.callID == part.callID\\n00690| and state.current_permission.tool.messageID == part.messageID\\n00691| )\\n00692| ---@TODO this is for backward compatibility, remove later\\n00693| or (state.current_permission.messageID == part.messageID and state.current_permission.callID == part.callID)\\n00694| )\\n00695| then\\n00696| M._handle_permission_request(output, part)\\n00697| end\\n00698| \\n00699| local end_line = output:get_line_count()\\n00700| if end_line - start_line > 1 then\\n00701| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1)\\n00702| end\\n00703| end\\n00704| \\n00705| ---@param output Output Output object to write to\\n00706| ---@param input TaskToolInput data for the tool\\n00707| ---@param metadata TaskToolMetadata Metadata for the tool use\\n00708| ---@param tool_output string\\n00709| function M._format_task_tool(output, input, metadata, tool_output)\\n00710| local start_line = output:get_line_count() + 1\\n00711| M._format_action(output, icons.get('task') .. ' task', input and input.description)\\n00712| \\n00713| if config.ui.output.tools.show_output then\\n00714| if tool_output and tool_output ~= '' then\\n00715| output:add_empty_line()\\n00716| output:add_lines(vim.split(tool_output, '\\\\n'))\\n00717| output:add_empty_line()\\n00718| end\\n00719| \\n00720| if metadata.summary and type(metadata.summary) == 'table' then\\n00721| for _, sub_part in ipairs(metadata.summary) do\\n00722| if sub_part.type == 'tool' and sub_part.tool then\\n00723| M._format_tool(output, sub_part)\\n00724| end\\n00725| end\\n00726| end\\n00727| end\\n00728| \\n00729| local end_line = output:get_line_count()\\n00730| output:add_action({\\n00731| text = '[S]elect Child Session',\\n00732| type = 'select_child_session',\\n00733| args = {},\\n00734| key = 'S',\\n00735| display_line = start_line - 1,\\n00736| range = { from = start_line, to = end_line },\\n00737| })\\n00738| end\\n00739| \\n00740| ---@param output Output Output object to write to\\n00741| ---@param lines string[]\\n00742| ---@param language string\\n00743| function M._format_code(output, lines, language)\\n00744| output:add_empty_line()\\n00745| --- NOTE: use longer code fence because lines could contain ```\\n00746| output:add_line('`````' .. (language or ''))\\n00747| output:add_lines(util.sanitize_lines(lines))\\n00748| output:add_line('`````')\\n00749| end\\n00750| \\n00751| ---@param output Output Output object to write to\\n00752| ---@param code string\\n00753| ---@param file_type string\\n00754| function M._format_diff(output, code, file_type)\\n00755| output:add_empty_line()\\n00756| \\n00757| --- NOTE: use longer code fence because code could contain ```\\n00758| output:add_line('`````' .. file_type)\\n00759| local lines = vim.split(code, '\\\\n')\\n00760| if #lines > 5 then\\n00761| lines = vim.list_slice(lines, 6)\\n00762| end\\n00763| \\n00764| for _, line in ipairs(lines) do\\n00765| local first_char = line:sub(1, 1)\\n00766| if first_char == '+' or first_char == '-' then\\n00767| local hl_group = first_char == '+' and 'OpencodeDiffAdd' or 'OpencodeDiffDelete'\\n00768| output:add_line(' ' .. line:sub(2))\\n00769| local line_idx = output:get_line_count()\\n00770| output:add_extmark(line_idx - 1, function()\\n00771| return {\\n00772| end_col = 0,\\n00773| end_row = line_idx,\\n00774| virt_text = { { first_char, hl_group } },\\n00775| hl_group = hl_group,\\n00776| hl_eol = true,\\n00777| priority = 5000,\\n00778| right_gravity = true,\\n00779| end_right_gravity = false,\\n00780| virt_text_hide = false,\\n00781| virt_text_pos = 'overlay',\\n00782| virt_text_repeat_linebreak = false,\\n00783| }\\n00784| end)\\n00785| else\\n00786| output:add_line(line)\\n00787| end\\n00788| end\\n00789| output:add_line('`````')\\n00790| end\\n00791| \\n00792| ---@param output Output Output object to write to\\n00793| ---@param start_line number\\n00794| ---@param end_line number\\n00795| ---@param hl_group string Highlight group for the border character\\n00796| ---@param win_col number\\n00797| ---@param text_hl_group? string Optional highlight group for the background/foreground of text lines\\n00798| function M._add_vertical_border(output, start_line, end_line, hl_group, win_col, text_hl_group)\\n00799| for line = start_line, end_line do\\n00800| local extmark_opts = {\\n00801| virt_text = { { require('opencode.ui.icons').get('border'), hl_group } },\\n00802| virt_text_pos = 'overlay',\\n00803| virt_text_win_col = win_col,\\n00804| virt_text_repeat_linebreak = true,\\n00805| }\\n00806| \\n00807| -- Add line highlight if text_hl_group is provided\\n00808| if text_hl_group then\\n00809| extmark_opts.line_hl_group = text_hl_group\\n00810| end\\n00811| \\n00812| output:add_extmark(line - 1, extmark_opts --[[@as OutputExtmark]])\\n00813| end\\n00814| end\\n00815| \\n00816| ---Formats a single message part and returns the resulting output object\\n00817| ---@param part OpencodeMessagePart The part to format\\n00818| ---@param message? OpencodeMessage Optional message object to extract role and mentions from\\n00819| ---@param is_last_part? boolean Whether this is the last part in the message, used to show an error if there is one\\n00820| ---@return Output\\n00821| function M.format_part(part, message, is_last_part)\\n00822| local output = Output.new()\\n00823| \\n00824| if not message or not message.info or not message.info.role then\\n00825| return output\\n00826| end\\n00827| \\n00828| local content_added = false\\n00829| local role = message.info.role\\n00830| \\n00831| if role == 'user' then\\n00832| if part.type == 'text' and part.text then\\n00833| if part.synthetic == true then\\n00834| M._format_selection_context(output, part)\\n00835| M._format_cursor_data_context(output, part)\\n00836| M._format_diagnostics_context(output, part)\\n00837| else\\n00838| M._format_user_prompt(output, vim.trim(part.text), message)\\n00839| content_added = true\\n00840| end\\n00841| elseif part.type == 'file' then\\n00842| local file_line = M._format_context_file(output, part.filename)\\n00843| if file_line then\\n00844| M._add_vertical_border(output, file_line - 1, file_line, 'OpencodeMessageRoleUser', -3)\\n00845| content_added = true\\n00846| end\\n00847| end\\n00848| elseif role == 'assistant' then\\n00849| if part.type == 'text' and part.text then\\n00850| M._format_assistant_message(output, vim.trim(part.text))\\n00851| content_added = true\\n00852| elseif part.type == 'reasoning' and part.text then\\n00853| M._format_reasoning(output, part)\\n00854| content_added = true\\n00855| elseif part.type == 'tool' then\\n00856| M._format_tool(output, part)\\n00857| content_added = true\\n00858| elseif part.type == 'patch' and part.hash then\\n00859| M._format_patch(output, part)\\n00860| content_added = true\\n00861| end\\n00862| end\\n00863| \\n00864| if content_added then\\n00865| output:add_empty_line()\\n00866| end\\n00867| \\n00868| if is_last_part and role == 'assistant' and message.info.error and message.info.error ~= '' then\\n00869| local error = message.info.error\\n00870| local error_message = error.data and error.data.message or vim.inspect(error)\\n00871| M._format_callout(output, 'ERROR', error_message)\\n00872| output:add_empty_line()\\n00873| end\\n00874| \\n00875| return output\\n00876| end\\n00877| \\n00878| return M\\n00879| \\n\\n(End of file - total 879 lines)\\n\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"file\",\"url\":\"file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\",\"id\":\"prt_b8e7c60a7002ybV09VDHoQQeO7\",\"filename\":\"lua/opencode/ui/formatter.lua\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"mime\":\"text/plain\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3002XHHlk77vAPApvR\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"{\\\"content\\\":[{\\\"msg\\\":\\\"expected `SessionRevertInfo` but found `SessionRevertInfo?`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l156:c68\\\"},{\\\"msg\\\":\\\"expected `integer?` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l490:c43\\\"},{\\\"msg\\\":\\\"expected `integer` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l492:c45\\\"},{\\\"msg\\\":\\\"expected `integer?` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l492:c62\\\"},{\\\"msg\\\":\\\"state.active_session may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l156:c68\\\"},{\\\"msg\\\":\\\"state.messages[#state.messages] may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l272:c74\\\"},{\\\"msg\\\":\\\"state.messages may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l272:c74\\\"},{\\\"msg\\\":\\\"Undefined field `[diag.severity]`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l435:c42\\\"},{\\\"msg\\\":\\\"Undefined field `command`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l526:c34\\\"},{\\\"msg\\\":\\\"Undefined field `command`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l527:c47\\\"},{\\\"msg\\\":\\\"Cannot assign `number` to `integer`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l493:c5\\\"}],\\\"context_type\\\":\\\"diagnostics\\\"}\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"time\":{\"updated\":1767622074603,\"created\":1767622072149}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"providerID\":\"github-copilot\",\"role\":\"assistant\",\"path\":{\"root\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"cwd\":\"/home/francis/Projects/_nvim/opencode.nvim\"},\"agent\":\"build\",\"time\":{\"created\":1767622074609},\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"mode\":\"build\",\"modelID\":\"gpt-4.1\",\"id\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"parentID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"cost\":0,\"tokens\":{\"output\":0,\"reasoning\":0,\"input\":0,\"cache\":{\"write\":0,\"read\":0}}}},\"type\":\"message.updated\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"created\":1767622074530},\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"summary\":{\"diffs\":[]}}},\"type\":\"message.updated\"},{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"updated\":1767622074670,\"created\":1767622072149},\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"summary\":{\"deletions\":0,\"additions\":0,\"files\":0}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"step-start\",\"id\":\"prt_b8e7c6672001F10WAiQKbzNEtE\",\"snapshot\":\"5ba6e95774829e7f501299039b72b72dc32c6620\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"tool\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"id\":\"prt_b8e7c6686001cCV44vsFtbpF42\",\"state\":{\"status\":\"pending\",\"input\":{},\"raw\":\"\"},\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\",\"tool\":\"bash\"}},\"type\":\"message.part.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"tool\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"id\":\"prt_b8e7c6686001cCV44vsFtbpF42\",\"state\":{\"status\":\"running\",\"input\":{\"description\":\"Shows working tree status\",\"command\":\"git status\"},\"time\":{\"start\":1767622076189}},\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\",\"tool\":\"bash\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"tool\":{\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\"},\"patterns\":[\"git status\"],\"id\":\"per_b8e7c6744001DX6EZ9KHM15RLi\",\"permission\":\"bash\",\"always\":[\"git status*\"],\"metadata\":{}},\"type\":\"permission.asked\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"created\":1767622074530},\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"summary\":{\"title\":\"Running git status to list changed files\",\"diffs\":[]}}},\"type\":\"message.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"title\":\"Running git status for formatter.lua changes\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"updated\":1767622082619,\"created\":1767622072149},\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"summary\":{\"deletions\":0,\"additions\":0,\"files\":0}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"}]\n",
+ "before": "",
+ "deletions": 0,
+ "additions": 1
+ }
+ ]
+ }
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "title": "Running git status for formatter.lua changes",
+ "version": "1.1.2",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "time": { "updated": 1767622106805, "created": 1767622072149 },
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "summary": { "deletions": 0, "additions": 1, "files": 1 }
+ }
+ },
+ "type": "session.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "step-start",
+ "id": "prt_b8e7ce0ca001Hb5Sp11isapDGi",
+ "snapshot": "34a4eef77f714f2e3a282c410dbda315c4781fee",
+ "messageID": "msg_b8e7cde9e0013hRkUyt0X2yMil"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "delta": " the",
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "messageID": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "id": "prt_b8e7ce0cc001nZUgxwsgHwogal",
+ "text": "Here are the",
+ "time": { "start": 1767622107340 }
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "delta": " according",
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "messageID": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "id": "prt_b8e7ce0cc001nZUgxwsgHwogal",
+ "text": "Here are the files that have been changed according",
+ "time": { "start": 1767622107340 }
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "delta": " staged",
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "messageID": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "id": "prt_b8e7ce0cc001nZUgxwsgHwogal",
+ "text": "Here are the files that have been changed according to git status:\n\n- Modified (but not staged",
+ "time": { "start": 1767622107340 }
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "delta": ".lua",
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "messageID": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "id": "prt_b8e7ce0cc001nZUgxwsgHwogal",
+ "text": "Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua",
+ "time": { "start": 1767622107340 }
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "delta": "formatter",
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "messageID": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "id": "prt_b8e7ce0cc001nZUgxwsgHwogal",
+ "text": "Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter",
+ "time": { "start": 1767622107340 }
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "delta": "/",
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "messageID": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "id": "prt_b8e7ce0cc001nZUgxwsgHwogal",
+ "text": "Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter.lua`\n - `lua/opencode/ui/",
+ "time": { "start": 1767622107340 }
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "delta": " -",
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "messageID": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "id": "prt_b8e7ce0cc001nZUgxwsgHwogal",
+ "text": "Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter.lua`\n - `lua/opencode/ui/renderer.lua`\n\n- Untracked files:\n -",
+ "time": { "start": 1767622107340 }
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "delta": "/",
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "messageID": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "id": "prt_b8e7ce0cc001nZUgxwsgHwogal",
+ "text": "Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter.lua`\n - `lua/opencode/ui/renderer.lua`\n\n- Untracked files:\n - `test.lua`\n - `tests/data/",
+ "time": { "start": 1767622107340 }
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "delta": " currently",
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "messageID": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "id": "prt_b8e7ce0cc001nZUgxwsgHwogal",
+ "text": "Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter.lua`\n - `lua/opencode/ui/renderer.lua`\n\n- Untracked files:\n - `test.lua`\n - `tests/data/permission_ask_new.json`\n\nNo files are currently",
+ "time": { "start": 1767622107340 }
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "delta": " want",
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "messageID": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "id": "prt_b8e7ce0cc001nZUgxwsgHwogal",
+ "text": "Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter.lua`\n - `lua/opencode/ui/renderer.lua`\n\n- Untracked files:\n - `test.lua`\n - `tests/data/permission_ask_new.json`\n\nNo files are currently staged for commit. Let me know if you want",
+ "time": { "start": 1767622107340 }
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "delta": " stage",
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "messageID": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "id": "prt_b8e7ce0cc001nZUgxwsgHwogal",
+ "text": "Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter.lua`\n - `lua/opencode/ui/renderer.lua`\n\n- Untracked files:\n - `test.lua`\n - `tests/data/permission_ask_new.json`\n\nNo files are currently staged for commit. Let me know if you want more details (like the diff), want to stage",
+ "time": { "start": 1767622107340 }
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "delta": "!",
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "messageID": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "id": "prt_b8e7ce0cc001nZUgxwsgHwogal",
+ "text": "Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter.lua`\n - `lua/opencode/ui/renderer.lua`\n\n- Untracked files:\n - `test.lua`\n - `tests/data/permission_ask_new.json`\n\nNo files are currently staged for commit. Let me know if you want more details (like the diff), want to stage/commit, or need help with anything else!",
+ "time": { "start": 1767622107340 }
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "messageID": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "id": "prt_b8e7ce0cc001nZUgxwsgHwogal",
+ "text": "Here are the files that have been changed according to git status:\n\n- Modified (but not staged):\n - `lua/opencode/event_manager.lua`\n - `lua/opencode/ui/formatter.lua`\n - `lua/opencode/ui/renderer.lua`\n\n- Untracked files:\n - `test.lua`\n - `tests/data/permission_ask_new.json`\n\nNo files are currently staged for commit. Let me know if you want more details (like the diff), want to stage/commit, or need help with anything else!",
+ "time": { "start": 1767622108550, "end": 1767622108550 }
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "step-finish",
+ "messageID": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "id": "prt_b8e7ce5860011MSYAyLSbWKBop",
+ "reason": "stop",
+ "cost": 0,
+ "snapshot": "34a4eef77f714f2e3a282c410dbda315c4781fee",
+ "tokens": { "output": 111, "reasoning": 0, "input": 179, "cache": { "write": 0, "read": 20864 } }
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "providerID": "github-copilot",
+ "role": "assistant",
+ "path": {
+ "root": "/home/francis/Projects/_nvim/opencode.nvim",
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "agent": "build",
+ "finish": "stop",
+ "time": { "created": 1767622106782 },
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "mode": "build",
+ "modelID": "gpt-4.1",
+ "id": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "parentID": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "cost": 0,
+ "tokens": { "output": 111, "reasoning": 0, "input": 179, "cache": { "write": 0, "read": 20864 } }
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "providerID": "github-copilot",
+ "role": "assistant",
+ "path": {
+ "root": "/home/francis/Projects/_nvim/opencode.nvim",
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "agent": "build",
+ "finish": "stop",
+ "time": { "created": 1767622106782, "completed": 1767622108574 },
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "mode": "build",
+ "modelID": "gpt-4.1",
+ "id": "msg_b8e7cde9e0013hRkUyt0X2yMil",
+ "parentID": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "cost": 0,
+ "tokens": { "output": 111, "reasoning": 0, "input": 179, "cache": { "write": 0, "read": 20864 } }
+ }
+ },
+ "type": "message.updated"
+ },
+ { "properties": { "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8" }, "type": "session.idle" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "time": { "created": 1767622074530 },
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "role": "user",
+ "id": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "agent": "build",
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "summary": {
+ "title": "Running git status to list changed files",
+ "diffs": [
+ {
+ "file": "tests/data/permission_ask_new.json",
+ "after": "[{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"time\":{\"updated\":1767622072149,\"created\":1767622072149}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"time\":{\"created\":1767622074530}}},\"type\":\"message.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3001M2zsH9REfPdlQt\",\"text\":\"@no-trust run a git status and tell me what files are changed\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3003Ta9NcXkN0lb0lF\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"Called the Read tool with the following input: {\\\"filePath\\\":\\\"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\\\"}\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a7001d3WhKOu2vCR4Cf\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"\\n00001| local context_module = require('opencode.context')\\n00002| local icons = require('opencode.ui.icons')\\n00003| local util = require('opencode.util')\\n00004| local Output = require('opencode.ui.output')\\n00005| local state = require('opencode.state')\\n00006| local config = require('opencode.config')\\n00007| local snapshot = require('opencode.snapshot')\\n00008| local mention = require('opencode.ui.mention')\\n00009| \\n00010| local M = {}\\n00011| \\n00012| M.separator = {\\n00013| '----',\\n00014| '',\\n00015| }\\n00016| \\n00017| ---@param output Output\\n00018| ---@param part OpencodeMessagePart\\n00019| function M._format_reasoning(output, part)\\n00020| local text = vim.trim(part.text or '')\\n00021| if text == '' then\\n00022| return\\n00023| end\\n00024| \\n00025| local start_line = output:get_line_count() + 1\\n00026| \\n00027| local title = 'Reasoning'\\n00028| local time = part.time\\n00029| if time and type(time) == 'table' and time.start then\\n00030| local start_text = util.format_time(time.start) or ''\\n00031| local end_text = (time['end'] and util.format_time(time['end'])) or nil\\n00032| if end_text and end_text ~= '' then\\n00033| title = string.format('%s (%s - %s)', title, start_text, end_text)\\n00034| elseif start_text ~= '' then\\n00035| title = string.format('%s (%s)', title, start_text)\\n00036| end\\n00037| end\\n00038| \\n00039| M._format_action(output, icons.get('reasoning') .. ' ' .. title, '')\\n00040| \\n00041| if config.ui.output.tools.show_reasoning_output then\\n00042| output:add_empty_line()\\n00043| output:add_lines(vim.split(text, '\\\\n'))\\n00044| output:add_empty_line()\\n00045| end\\n00046| \\n00047| local end_line = output:get_line_count()\\n00048| if end_line - start_line > 1 then\\n00049| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1, 'OpencodeReasoningText')\\n00050| else\\n00051| output:add_extmark(start_line - 1, {\\n00052| line_hl_group = 'OpencodeReasoningText',\\n00053| } --[[@as OutputExtmark]])\\n00054| end\\n00055| end\\n00056| \\n00057| function M._handle_permission_request(output, part)\\n00058| if part.state and part.state.status == 'error' and part.state.error then\\n00059| if part.state.error:match('rejected permission') then\\n00060| state.current_permission = nil\\n00061| else\\n00062| vim.notify('Unknown part state error: ' .. part.state.error)\\n00063| end\\n00064| return\\n00065| end\\n00066| \\n00067| M._format_permission_request(output)\\n00068| end\\n00069| \\n00070| function M._format_permission_request(output)\\n00071| local keys\\n00072| \\n00073| if require('opencode.ui.ui').is_opencode_focused() then\\n00074| keys = {\\n00075| config.keymap.permission.accept,\\n00076| config.keymap.permission.accept_all,\\n00077| config.keymap.permission.deny,\\n00078| }\\n00079| else\\n00080| keys = {\\n00081| config.get_key_for_function('editor', 'permission_accept'),\\n00082| config.get_key_for_function('editor', 'permission_accept_all'),\\n00083| config.get_key_for_function('editor', 'permission_deny'),\\n00084| }\\n00085| end\\n00086| \\n00087| output:add_empty_line()\\n00088| output:add_line('> [!WARNING] Permission required to run this tool.')\\n00089| output:add_line('>')\\n00090| output:add_line(('> Accept `%s` Always `%s` Deny `%s`'):format(unpack(keys)))\\n00091| output:add_empty_line()\\n00092| end\\n00093| \\n00094| ---Calculate statistics for reverted messages and tool calls\\n00095| ---@param messages {info: MessageInfo, parts: OpencodeMessagePart[]}[] All messages in the session\\n00096| ---@param revert_index number Index of the message where revert occurred\\n00097| ---@param revert_info SessionRevertInfo Revert information\\n00098| ---@return {messages: number, tool_calls: number, files: table}\\n00099| function M._calculate_revert_stats(messages, revert_index, revert_info)\\n00100| local stats = {\\n00101| messages = 0,\\n00102| tool_calls = 0,\\n00103| files = {}, -- { [filename] = { additions = n, deletions = m } }\\n00104| }\\n00105| \\n00106| for i = revert_index, #messages do\\n00107| local msg = messages[i]\\n00108| if msg.info.role == 'user' then\\n00109| stats.messages = stats.messages + 1\\n00110| end\\n00111| if msg.parts then\\n00112| for _, part in ipairs(msg.parts) do\\n00113| if part.type == 'tool' then\\n00114| stats.tool_calls = stats.tool_calls + 1\\n00115| end\\n00116| end\\n00117| end\\n00118| end\\n00119| \\n00120| if revert_info.diff then\\n00121| local current_file = nil\\n00122| for line in revert_info.diff:gmatch('[^\\\\r\\\\n]+') do\\n00123| local file_a = line:match('^%-%-%- ([ab]/.+)')\\n00124| local file_b = line:match('^%+%+%+ ([ab]/.+)')\\n00125| if file_b then\\n00126| current_file = file_b:gsub('^[ab]/', '')\\n00127| if not stats.files[current_file] then\\n00128| stats.files[current_file] = { additions = 0, deletions = 0 }\\n00129| end\\n00130| elseif file_a then\\n00131| current_file = file_a:gsub('^[ab]/', '')\\n00132| if not stats.files[current_file] then\\n00133| stats.files[current_file] = { additions = 0, deletions = 0 }\\n00134| end\\n00135| elseif line:sub(1, 1) == '+' and not line:match('^%+%+%+') then\\n00136| if current_file then\\n00137| stats.files[current_file].additions = stats.files[current_file].additions + 1\\n00138| end\\n00139| elseif line:sub(1, 1) == '-' and not line:match('^%-%-%-') then\\n00140| if current_file then\\n00141| stats.files[current_file].deletions = stats.files[current_file].deletions + 1\\n00142| end\\n00143| end\\n00144| end\\n00145| end\\n00146| \\n00147| return stats\\n00148| end\\n00149| \\n00150| ---Format the revert callout with statistics\\n00151| ---@param session_data OpencodeMessage[] All messages in the session\\n00152| ---@param start_idx number Index of the message where revert occurred\\n00153| ---@return Output output object representing the lines, extmarks, and actions\\n00154| function M._format_revert_message(session_data, start_idx)\\n00155| local output = Output.new()\\n00156| local stats = M._calculate_revert_stats(session_data, start_idx, state.active_session.revert)\\n00157| local message_text = stats.messages == 1 and 'message' or 'messages'\\n00158| local tool_text = stats.tool_calls == 1 and 'tool call' or 'tool calls'\\n00159| \\n00160| output:add_lines(M.separator)\\n00161| output:add_line(\\n00162| string.format('> %d %s reverted, %d %s reverted', stats.messages, message_text, stats.tool_calls, tool_text)\\n00163| )\\n00164| output:add_line('>')\\n00165| output:add_line('> type `/redo` to restore.')\\n00166| output:add_empty_line()\\n00167| \\n00168| if stats.files and next(stats.files) then\\n00169| for file, fstats in pairs(stats.files) do\\n00170| local file_diff = {}\\n00171| if fstats.additions > 0 then\\n00172| table.insert(file_diff, '+' .. fstats.additions)\\n00173| end\\n00174| if fstats.deletions > 0 then\\n00175| table.insert(file_diff, '-' .. fstats.deletions)\\n00176| end\\n00177| if #file_diff > 0 then\\n00178| local line_str = string.format(icons.get('file') .. '%s: %s', file, table.concat(file_diff, ' '))\\n00179| local line_idx = output:add_line(line_str)\\n00180| local col = #(' ' .. file .. ': ')\\n00181| for _, diff in ipairs(file_diff) do\\n00182| local hl_group = diff:sub(1, 1) == '+' and 'OpencodeDiffAddText' or 'OpencodeDiffDeleteText'\\n00183| output:add_extmark(line_idx - 1, {\\n00184| virt_text = { { diff, hl_group } },\\n00185| virt_text_pos = 'inline',\\n00186| virt_text_win_col = col,\\n00187| priority = 1000,\\n00188| } --[[@as OutputExtmark]])\\n00189| col = col + #diff + 1\\n00190| end\\n00191| end\\n00192| end\\n00193| end\\n00194| return output\\n00195| end\\n00196| \\n00197| local function add_action(output, text, action_type, args, key, line)\\n00198| -- actions use api-indexing (e.g. 0 indexed)\\n00199| line = (line or output:get_line_count()) - 1\\n00200| output:add_action({\\n00201| text = text,\\n00202| type = action_type,\\n00203| args = args,\\n00204| key = key,\\n00205| display_line = line,\\n00206| range = { from = line, to = line },\\n00207| })\\n00208| end\\n00209| \\n00210| ---@param output Output Output object to write to\\n00211| ---@param part OpencodeMessagePart\\n00212| function M._format_patch(output, part)\\n00213| if not part.hash then\\n00214| return\\n00215| end\\n00216| \\n00217| local restore_points = snapshot.get_restore_points_by_parent(part.hash) or {}\\n00218| M._format_action(output, icons.get('snapshot') .. ' Created Snapshot', vim.trim(part.hash:sub(1, 8)))\\n00219| \\n00220| -- Anchor all snapshot-level actions to the snapshot header line\\n00221| add_action(output, '[R]evert file', 'diff_revert_selected_file', { part.hash }, 'R')\\n00222| add_action(output, 'Revert [A]ll', 'diff_revert_all', { part.hash }, 'A')\\n00223| add_action(output, '[D]iff', 'diff_open', { part.hash }, 'D')\\n00224| \\n00225| if #restore_points > 0 then\\n00226| for _, restore_point in ipairs(restore_points) do\\n00227| output:add_line(\\n00228| string.format(\\n00229| ' %s Restore point `%s` - %s ',\\n00230| icons.get('restore_point'),\\n00231| vim.trim(restore_point.id:sub(1, 8)),\\n00232| util.format_time(restore_point.created_at)\\n00233| )\\n00234| )\\n00235| add_action(output, 'Restore [A]ll', 'diff_restore_snapshot_all', { restore_point.id }, 'A')\\n00236| add_action(output, '[R]estore file', 'diff_restore_snapshot_file', { restore_point.id }, 'R')\\n00237| end\\n00238| end\\n00239| end\\n00240| \\n00241| ---@param output Output Output object to write to\\n00242| ---@param message MessageInfo\\n00243| function M._format_error(output, message)\\n00244| output:add_empty_line()\\n00245| M._format_callout(output, 'ERROR', vim.inspect(message.error))\\n00246| end\\n00247| \\n00248| ---@param message OpencodeMessage\\n00249| ---@return Output\\n00250| function M.format_message_header(message)\\n00251| local output = Output.new()\\n00252| \\n00253| output:add_lines(M.separator)\\n00254| local role = message.info.role or 'unknown'\\n00255| local icon = message.info.role == 'user' and icons.get('header_user') or icons.get('header_assistant')\\n00256| \\n00257| local time = message.info.time and message.info.time.created or nil\\n00258| local time_text = (time and ' (' .. util.format_time(time) .. ')' or '')\\n00259| local role_hl = 'OpencodeMessageRole' .. role:sub(1, 1):upper() .. role:sub(2)\\n00260| local model_text = message.info.modelID and ' ' .. message.info.modelID or ''\\n00261| \\n00262| local debug_text = config.debug.show_ids and ' [' .. message.info.id .. ']' or ''\\n00263| \\n00264| local display_name\\n00265| if role == 'assistant' then\\n00266| local mode = message.info.mode\\n00267| if mode and mode ~= '' then\\n00268| display_name = mode:upper()\\n00269| else\\n00270| -- For the most recent assistant message, show current_mode if mode is missing\\n00271| -- This handles new messages that haven't been stamped yet\\n00272| local is_last_message = #state.messages == 0 or message.info.id == state.messages[#state.messages].info.id\\n00273| if is_last_message and state.current_mode and state.current_mode ~= '' then\\n00274| display_name = state.current_mode:upper()\\n00275| else\\n00276| display_name = 'ASSISTANT'\\n00277| end\\n00278| end\\n00279| else\\n00280| display_name = role:upper()\\n00281| end\\n00282| \\n00283| output:add_extmark(output:get_line_count() - 1, {\\n00284| virt_text = {\\n00285| { icon, role_hl },\\n00286| { ' ' },\\n00287| { display_name, role_hl },\\n00288| { model_text, 'OpencodeHint' },\\n00289| { time_text, 'OpencodeHint' },\\n00290| { debug_text, 'OpencodeHint' },\\n00291| },\\n00292| virt_text_win_col = -3,\\n00293| priority = 10,\\n00294| } --[[@as OutputExtmark]])\\n00295| \\n00296| -- Only want to show the error if we have no parts. If we have parts, they'll\\n00297| -- handle rendering the error\\n00298| if\\n00299| role == 'assistant'\\n00300| and message.info.error\\n00301| and message.info.error ~= ''\\n00302| and (not message.parts or #message.parts == 0)\\n00303| then\\n00304| local error = message.info.error\\n00305| local error_message = error.data and error.data.message or vim.inspect(error)\\n00306| \\n00307| output:add_line('')\\n00308| M._format_callout(output, 'ERROR', error_message)\\n00309| end\\n00310| \\n00311| output:add_line('')\\n00312| return output\\n00313| end\\n00314| \\n00315| ---@param output Output Output object to write to\\n00316| ---@param callout string Callout type (e.g., 'ERROR', 'TODO')\\n00317| ---@param text string Callout text content\\n00318| ---@param title? string Optional title for the callout\\n00319| function M._format_callout(output, callout, text, title)\\n00320| title = title and title .. ' ' or ''\\n00321| local win_width = (state.windows and state.windows.output_win and vim.api.nvim_win_is_valid(state.windows.output_win))\\n00322| and vim.api.nvim_win_get_width(state.windows.output_win)\\n00323| or config.ui.window_width\\n00324| or 80\\n00325| if #text > win_width - 4 then\\n00326| local ok, substituted = pcall(vim.fn.substitute, text, '\\\\v(.{' .. (win_width - 8) .. '})', '\\\\1\\\\n', 'g')\\n00327| text = ok and substituted or text\\n00328| end\\n00329| \\n00330| -- Trim off any trailing newlines so there isn't an extra line in the\\n00331| -- extmarks section\\n00332| local lines = vim.split(text:gsub('\\\\n$', ''), '\\\\n')\\n00333| if #lines == 1 and title == '' then\\n00334| output:add_line('> [!' .. callout .. '] ' .. lines[1])\\n00335| else\\n00336| output:add_line('> [!' .. callout .. ']' .. title)\\n00337| output:add_line('>')\\n00338| output:add_lines(lines, '> ')\\n00339| end\\n00340| end\\n00341| \\n00342| ---@param output Output Output object to write to\\n00343| ---@param text string\\n00344| ---@param message? OpencodeMessage Optional message object to extract mentions from\\n00345| function M._format_user_prompt(output, text, message)\\n00346| local start_line = output:get_line_count()\\n00347| \\n00348| output:add_lines(vim.split(text, '\\\\n'))\\n00349| \\n00350| local end_line = output:get_line_count()\\n00351| \\n00352| local end_line_extmark_offset = 0\\n00353| \\n00354| local mentions = {}\\n00355| if message and message.parts then\\n00356| -- message.parts will only be filled out on a re-render\\n00357| -- we need to collect the mentions here\\n00358| for _, part in ipairs(message.parts) do\\n00359| if part.type == 'file' then\\n00360| -- we're rerendering this part and we have files, the space after the user prompt\\n00361| -- also needs an extmark\\n00362| end_line_extmark_offset = 1\\n00363| if part.source and part.source.text then\\n00364| table.insert(mentions, part.source.text)\\n00365| end\\n00366| elseif part.type == 'agent' then\\n00367| if part.source then\\n00368| table.insert(mentions, part.source)\\n00369| end\\n00370| end\\n00371| end\\n00372| end\\n00373| \\n00374| if #mentions > 0 then\\n00375| mention.highlight_mentions_in_output(output, text, mentions, start_line)\\n00376| end\\n00377| \\n00378| M._add_vertical_border(output, start_line, end_line + end_line_extmark_offset, 'OpencodeMessageRoleUser', -3)\\n00379| end\\n00380| \\n00381| ---@param output Output Output object to write to\\n00382| ---@param part OpencodeMessagePart\\n00383| function M._format_selection_context(output, part)\\n00384| local json = context_module.decode_json_context(part.text or '', 'selection')\\n00385| if not json then\\n00386| return\\n00387| end\\n00388| local start_line = output:get_line_count()\\n00389| output:add_lines(vim.split(json.content or '', '\\\\n'))\\n00390| output:add_empty_line()\\n00391| \\n00392| local end_line = output:get_line_count()\\n00393| \\n00394| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00395| end\\n00396| \\n00397| ---@param output Output Output object to write to\\n00398| ---@param part OpencodeMessagePart\\n00399| function M._format_cursor_data_context(output, part)\\n00400| local json = context_module.decode_json_context(part.text or '', 'cursor-data')\\n00401| if not json then\\n00402| return\\n00403| end\\n00404| local start_line = output:get_line_count()\\n00405| output:add_line('Line ' .. json.line .. ':')\\n00406| output:add_lines(vim.split(json.line_content or '', '\\\\n'))\\n00407| output:add_empty_line()\\n00408| \\n00409| local end_line = output:get_line_count()\\n00410| \\n00411| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00412| end\\n00413| \\n00414| ---@param output Output Output object to write to\\n00415| ---@param part OpencodeMessagePart\\n00416| function M._format_diagnostics_context(output, part)\\n00417| local json = context_module.decode_json_context(part.text or '', 'diagnostics')\\n00418| if not json then\\n00419| return\\n00420| end\\n00421| local start_line = output:get_line_count()\\n00422| local diagnostics = json.content --[[@as OpencodeDiagnostic[] ]]\\n00423| if not diagnostics or type(diagnostics) ~= 'table' or #diagnostics == 0 then\\n00424| return\\n00425| end\\n00426| \\n00427| local diagnostics_count = { error = 0, warn = 0, info = 0 }\\n00428| local diagnostics_icons = {\\n00429| error = icons.get('error'),\\n00430| warn = icons.get('warning'),\\n00431| info = icons.get('info'),\\n00432| }\\n00433| \\n00434| for _, diag in ipairs(diagnostics) do\\n00435| local name = vim.diagnostic.severity[diag.severity]:lower()\\n00436| diagnostics_count[name] = diagnostics_count[name] + 1\\n00437| end\\n00438| \\n00439| local diag_line = '**Diagnostics:**'\\n00440| for name, count in pairs(diagnostics_count) do\\n00441| if count > 0 then\\n00442| diag_line = diag_line .. (string.format(' %s(%d)', diagnostics_icons[name], count))\\n00443| end\\n00444| end\\n00445| output:add_line(diag_line)\\n00446| output:add_empty_line()\\n00447| local end_line = output:get_line_count()\\n00448| \\n00449| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00450| end\\n00451| \\n00452| ---Format and display the file path in the context\\n00453| ---@param output Output Output object to write to\\n00454| ---@param path string|nil File path\\n00455| function M._format_context_file(output, path)\\n00456| if not path or path == '' then\\n00457| return\\n00458| end\\n00459| local cwd = vim.fn.getcwd()\\n00460| if vim.startswith(path, cwd) then\\n00461| path = path:sub(#cwd + 2)\\n00462| end\\n00463| return output:add_line(string.format('[%s](%s)', path, path))\\n00464| end\\n00465| \\n00466| ---@param output Output Output object to write to\\n00467| ---@param text string\\n00468| function M._format_assistant_message(output, text)\\n00469| local reference_picker = require('opencode.ui.reference_picker')\\n00470| local references = reference_picker.parse_references(text, '')\\n00471| \\n00472| -- If no references, just add the text as-is\\n00473| if #references == 0 then\\n00474| output:add_lines(vim.split(text, '\\\\n'))\\n00475| return\\n00476| end\\n00477| \\n00478| -- Sort references by match_start position (ascending)\\n00479| table.sort(references, function(a, b)\\n00480| return a.match_start < b.match_start\\n00481| end)\\n00482| \\n00483| -- Build a new text with icons inserted before each reference\\n00484| local result = ''\\n00485| local last_pos = 1\\n00486| local ref_icon = icons.get('reference')\\n00487| \\n00488| for _, ref in ipairs(references) do\\n00489| -- Add text before this reference\\n00490| result = result .. text:sub(last_pos, ref.match_start - 1)\\n00491| -- Add the icon and the reference\\n00492| result = result .. ref_icon .. text:sub(ref.match_start, ref.match_end)\\n00493| last_pos = ref.match_end + 1\\n00494| end\\n00495| \\n00496| -- Add any remaining text after the last reference\\n00497| if last_pos <= #text then\\n00498| result = result .. text:sub(last_pos)\\n00499| end\\n00500| \\n00501| output:add_lines(vim.split(result, '\\\\n'))\\n00502| end\\n00503| \\n00504| ---@param output Output Output object to write to\\n00505| ---@param tool_type string Tool type (e.g., 'run', 'read', 'edit', etc.)\\n00506| ---@param value string Value associated with the action (e.g., filename, command)\\n00507| function M._format_action(output, tool_type, value)\\n00508| if not tool_type or not value then\\n00509| return\\n00510| end\\n00511| local line = string.format('**%s** %s', tool_type, value and #value > 0 and ('`' .. value .. '`') or '')\\n00512| \\n00513| output:add_line(line)\\n00514| end\\n00515| \\n00516| ---@param output Output Output object to write to\\n00517| ---@param input BashToolInput data for the tool\\n00518| ---@param metadata BashToolMetadata Metadata for the tool use\\n00519| function M._format_bash_tool(output, input, metadata)\\n00520| M._format_action(output, icons.get('run') .. ' run', input and input.description)\\n00521| \\n00522| if not config.ui.output.tools.show_output then\\n00523| return\\n00524| end\\n00525| \\n00526| if metadata.output or metadata.command or input.command then\\n00527| local command = input.command or metadata.command or ''\\n00528| local command_output = metadata.output and metadata.output ~= '' and ('\\\\n' .. metadata.output) or ''\\n00529| M._format_code(output, vim.split('> ' .. command .. '\\\\n' .. command_output, '\\\\n'), 'bash')\\n00530| end\\n00531| end\\n00532| \\n00533| ---@param output Output Output object to write to\\n00534| ---@param tool_type string Tool type (e.g., 'read', 'edit', 'write')\\n00535| ---@param input FileToolInput data for the tool\\n00536| ---@param metadata FileToolMetadata Metadata for the tool use\\n00537| function M._format_file_tool(output, tool_type, input, metadata)\\n00538| local file_name = input and vim.fn.fnamemodify(input.filePath, ':t') or ''\\n00539| local file_type = input and util.get_markdown_filetype(input.filePath) or ''\\n00540| local tool_action_icons = { read = icons.get('read'), edit = icons.get('edit'), write = icons.get('write') }\\n00541| \\n00542| M._format_action(output, tool_action_icons[tool_type] .. ' ' .. tool_type, file_name)\\n00543| \\n00544| if not config.ui.output.tools.show_output then\\n00545| return\\n00546| end\\n00547| \\n00548| if tool_type == 'edit' and metadata.diff then\\n00549| M._format_diff(output, metadata.diff, file_type)\\n00550| elseif tool_type == 'write' and input and input.content then\\n00551| M._format_code(output, vim.split(input.content, '\\\\n'), file_type)\\n00552| end\\n00553| end\\n00554| \\n00555| ---@param output Output Output object to write to\\n00556| ---@param title string\\n00557| ---@param input TodoToolInput\\n00558| function M._format_todo_tool(output, title, input)\\n00559| M._format_action(output, icons.get('plan') .. ' plan', (title or ''))\\n00560| if not config.ui.output.tools.show_output then\\n00561| return\\n00562| end\\n00563| \\n00564| local todos = input and input.todos or {}\\n00565| \\n00566| for _, item in ipairs(todos) do\\n00567| local statuses = { in_progress = '-', completed = 'x', pending = ' ' }\\n00568| output:add_line(string.format('- [%s] %s ', statuses[item.status], item.content))\\n00569| end\\n00570| end\\n00571| \\n00572| ---@param output Output Output object to write to\\n00573| ---@param input GlobToolInput data for the tool\\n00574| ---@param metadata GlobToolMetadata Metadata for the tool use\\n00575| function M._format_glob_tool(output, input, metadata)\\n00576| M._format_action(output, icons.get('search') .. ' glob', input and input.pattern)\\n00577| if not config.ui.output.tools.show_output then\\n00578| return\\n00579| end\\n00580| local prefix = metadata.truncated and ' more than' or ''\\n00581| output:add_line(string.format('Found%s `%d` file(s):', prefix, metadata.count or 0))\\n00582| end\\n00583| \\n00584| ---@param output Output Output object to write to\\n00585| ---@param input GrepToolInput data for the tool\\n00586| ---@param metadata GrepToolMetadata Metadata for the tool use\\n00587| function M._format_grep_tool(output, input, metadata)\\n00588| input = input or { path = '', include = '', pattern = '' }\\n00589| \\n00590| local grep_str = string.format('%s` `%s', (input.path or input.include) or '', input.pattern or '')\\n00591| \\n00592| M._format_action(output, icons.get('search') .. ' grep', grep_str)\\n00593| if not config.ui.output.tools.show_output then\\n00594| return\\n00595| end\\n00596| local prefix = metadata.truncated and ' more than' or ''\\n00597| output:add_line(\\n00598| string.format('Found%s `%d` match' .. (metadata.matches ~= 1 and 'es' or ''), prefix, metadata.matches or 0)\\n00599| )\\n00600| end\\n00601| \\n00602| ---@param output Output Output object to write to\\n00603| ---@param input WebFetchToolInput data for the tool\\n00604| function M._format_webfetch_tool(output, input)\\n00605| M._format_action(output, icons.get('web') .. ' fetch', input and input.url)\\n00606| end\\n00607| \\n00608| ---@param output Output Output object to write to\\n00609| ---@param input ListToolInput\\n00610| ---@param metadata ListToolMetadata\\n00611| ---@param tool_output string\\n00612| function M._format_list_tool(output, input, metadata, tool_output)\\n00613| M._format_action(output, icons.get('list') .. ' list', input and input.path or '')\\n00614| if not config.ui.output.tools.show_output then\\n00615| return\\n00616| end\\n00617| local lines = vim.split(vim.trim(tool_output or ''), '\\\\n')\\n00618| if #lines < 1 or metadata.count == 0 then\\n00619| output:add_line('No files found.')\\n00620| return\\n00621| end\\n00622| if #lines > 1 then\\n00623| output:add_line('Files:')\\n00624| for i = 2, #lines do\\n00625| local file = vim.trim(lines[i])\\n00626| if file ~= '' then\\n00627| output:add_line(' • ' .. file)\\n00628| end\\n00629| end\\n00630| end\\n00631| if metadata.truncated then\\n00632| output:add_line(string.format('Results truncated, showing first %d files', metadata.count or '?'))\\n00633| end\\n00634| end\\n00635| \\n00636| ---@param output Output Output object to write to\\n00637| ---@param part OpencodeMessagePart\\n00638| function M._format_tool(output, part)\\n00639| local tool = part.tool\\n00640| if not tool or not part.state then\\n00641| return\\n00642| end\\n00643| \\n00644| local start_line = output:get_line_count() + 1\\n00645| local input = part.state.input or {}\\n00646| local metadata = part.state.metadata or {}\\n00647| local tool_output = part.state.output or ''\\n00648| \\n00649| if state.current_permission and state.current_permission.messageID == part.messageID then\\n00650| metadata = state.current_permission.metadata or metadata\\n00651| end\\n00652| \\n00653| if tool == 'bash' then\\n00654| M._format_bash_tool(output, input --[[@as BashToolInput]], metadata --[[@as BashToolMetadata]])\\n00655| elseif tool == 'read' or tool == 'edit' or tool == 'write' then\\n00656| M._format_file_tool(output, tool, input --[[@as FileToolInput]], metadata --[[@as FileToolMetadata]])\\n00657| elseif tool == 'todowrite' then\\n00658| M._format_todo_tool(output, part.state.title, input --[[@as TodoToolInput]])\\n00659| elseif tool == 'glob' then\\n00660| M._format_glob_tool(output, input --[[@as GlobToolInput]], metadata --[[@as GlobToolMetadata]])\\n00661| elseif tool == 'list' then\\n00662| M._format_list_tool(output, input --[[@as ListToolInput]], metadata --[[@as ListToolMetadata]], tool_output)\\n00663| elseif tool == 'grep' then\\n00664| M._format_grep_tool(output, input --[[@as GrepToolInput]], metadata --[[@as GrepToolMetadata]])\\n00665| elseif tool == 'webfetch' then\\n00666| M._format_webfetch_tool(output, input --[[@as WebFetchToolInput]])\\n00667| elseif tool == 'task' then\\n00668| M._format_task_tool(output, input --[[@as TaskToolInput]], metadata --[[@as TaskToolMetadata]], tool_output)\\n00669| else\\n00670| M._format_action(output, icons.get('tool') .. ' tool', tool)\\n00671| end\\n00672| \\n00673| if part.state.status == 'error' and part.state.error then\\n00674| output:add_line('')\\n00675| M._format_callout(output, 'ERROR', part.state.error)\\n00676| ---@diagnostic disable-next-line: undefined-field\\n00677| elseif part.state.input and part.state.input.error then\\n00678| output:add_line('')\\n00679| ---I'm not sure about the type with state.input.error\\n00680| ---@diagnostic disable-next-line: undefined-field\\n00681| M._format_callout(output, 'ERROR', part.state.input.error)\\n00682| end\\n00683| \\n00684| if\\n00685| state.current_permission\\n00686| and (\\n00687| (\\n00688| state.current_permission.tool\\n00689| and state.current_permission.tool.callID == part.callID\\n00690| and state.current_permission.tool.messageID == part.messageID\\n00691| )\\n00692| ---@TODO this is for backward compatibility, remove later\\n00693| or (state.current_permission.messageID == part.messageID and state.current_permission.callID == part.callID)\\n00694| )\\n00695| then\\n00696| M._handle_permission_request(output, part)\\n00697| end\\n00698| \\n00699| local end_line = output:get_line_count()\\n00700| if end_line - start_line > 1 then\\n00701| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1)\\n00702| end\\n00703| end\\n00704| \\n00705| ---@param output Output Output object to write to\\n00706| ---@param input TaskToolInput data for the tool\\n00707| ---@param metadata TaskToolMetadata Metadata for the tool use\\n00708| ---@param tool_output string\\n00709| function M._format_task_tool(output, input, metadata, tool_output)\\n00710| local start_line = output:get_line_count() + 1\\n00711| M._format_action(output, icons.get('task') .. ' task', input and input.description)\\n00712| \\n00713| if config.ui.output.tools.show_output then\\n00714| if tool_output and tool_output ~= '' then\\n00715| output:add_empty_line()\\n00716| output:add_lines(vim.split(tool_output, '\\\\n'))\\n00717| output:add_empty_line()\\n00718| end\\n00719| \\n00720| if metadata.summary and type(metadata.summary) == 'table' then\\n00721| for _, sub_part in ipairs(metadata.summary) do\\n00722| if sub_part.type == 'tool' and sub_part.tool then\\n00723| M._format_tool(output, sub_part)\\n00724| end\\n00725| end\\n00726| end\\n00727| end\\n00728| \\n00729| local end_line = output:get_line_count()\\n00730| output:add_action({\\n00731| text = '[S]elect Child Session',\\n00732| type = 'select_child_session',\\n00733| args = {},\\n00734| key = 'S',\\n00735| display_line = start_line - 1,\\n00736| range = { from = start_line, to = end_line },\\n00737| })\\n00738| end\\n00739| \\n00740| ---@param output Output Output object to write to\\n00741| ---@param lines string[]\\n00742| ---@param language string\\n00743| function M._format_code(output, lines, language)\\n00744| output:add_empty_line()\\n00745| --- NOTE: use longer code fence because lines could contain ```\\n00746| output:add_line('`````' .. (language or ''))\\n00747| output:add_lines(util.sanitize_lines(lines))\\n00748| output:add_line('`````')\\n00749| end\\n00750| \\n00751| ---@param output Output Output object to write to\\n00752| ---@param code string\\n00753| ---@param file_type string\\n00754| function M._format_diff(output, code, file_type)\\n00755| output:add_empty_line()\\n00756| \\n00757| --- NOTE: use longer code fence because code could contain ```\\n00758| output:add_line('`````' .. file_type)\\n00759| local lines = vim.split(code, '\\\\n')\\n00760| if #lines > 5 then\\n00761| lines = vim.list_slice(lines, 6)\\n00762| end\\n00763| \\n00764| for _, line in ipairs(lines) do\\n00765| local first_char = line:sub(1, 1)\\n00766| if first_char == '+' or first_char == '-' then\\n00767| local hl_group = first_char == '+' and 'OpencodeDiffAdd' or 'OpencodeDiffDelete'\\n00768| output:add_line(' ' .. line:sub(2))\\n00769| local line_idx = output:get_line_count()\\n00770| output:add_extmark(line_idx - 1, function()\\n00771| return {\\n00772| end_col = 0,\\n00773| end_row = line_idx,\\n00774| virt_text = { { first_char, hl_group } },\\n00775| hl_group = hl_group,\\n00776| hl_eol = true,\\n00777| priority = 5000,\\n00778| right_gravity = true,\\n00779| end_right_gravity = false,\\n00780| virt_text_hide = false,\\n00781| virt_text_pos = 'overlay',\\n00782| virt_text_repeat_linebreak = false,\\n00783| }\\n00784| end)\\n00785| else\\n00786| output:add_line(line)\\n00787| end\\n00788| end\\n00789| output:add_line('`````')\\n00790| end\\n00791| \\n00792| ---@param output Output Output object to write to\\n00793| ---@param start_line number\\n00794| ---@param end_line number\\n00795| ---@param hl_group string Highlight group for the border character\\n00796| ---@param win_col number\\n00797| ---@param text_hl_group? string Optional highlight group for the background/foreground of text lines\\n00798| function M._add_vertical_border(output, start_line, end_line, hl_group, win_col, text_hl_group)\\n00799| for line = start_line, end_line do\\n00800| local extmark_opts = {\\n00801| virt_text = { { require('opencode.ui.icons').get('border'), hl_group } },\\n00802| virt_text_pos = 'overlay',\\n00803| virt_text_win_col = win_col,\\n00804| virt_text_repeat_linebreak = true,\\n00805| }\\n00806| \\n00807| -- Add line highlight if text_hl_group is provided\\n00808| if text_hl_group then\\n00809| extmark_opts.line_hl_group = text_hl_group\\n00810| end\\n00811| \\n00812| output:add_extmark(line - 1, extmark_opts --[[@as OutputExtmark]])\\n00813| end\\n00814| end\\n00815| \\n00816| ---Formats a single message part and returns the resulting output object\\n00817| ---@param part OpencodeMessagePart The part to format\\n00818| ---@param message? OpencodeMessage Optional message object to extract role and mentions from\\n00819| ---@param is_last_part? boolean Whether this is the last part in the message, used to show an error if there is one\\n00820| ---@return Output\\n00821| function M.format_part(part, message, is_last_part)\\n00822| local output = Output.new()\\n00823| \\n00824| if not message or not message.info or not message.info.role then\\n00825| return output\\n00826| end\\n00827| \\n00828| local content_added = false\\n00829| local role = message.info.role\\n00830| \\n00831| if role == 'user' then\\n00832| if part.type == 'text' and part.text then\\n00833| if part.synthetic == true then\\n00834| M._format_selection_context(output, part)\\n00835| M._format_cursor_data_context(output, part)\\n00836| M._format_diagnostics_context(output, part)\\n00837| else\\n00838| M._format_user_prompt(output, vim.trim(part.text), message)\\n00839| content_added = true\\n00840| end\\n00841| elseif part.type == 'file' then\\n00842| local file_line = M._format_context_file(output, part.filename)\\n00843| if file_line then\\n00844| M._add_vertical_border(output, file_line - 1, file_line, 'OpencodeMessageRoleUser', -3)\\n00845| content_added = true\\n00846| end\\n00847| end\\n00848| elseif role == 'assistant' then\\n00849| if part.type == 'text' and part.text then\\n00850| M._format_assistant_message(output, vim.trim(part.text))\\n00851| content_added = true\\n00852| elseif part.type == 'reasoning' and part.text then\\n00853| M._format_reasoning(output, part)\\n00854| content_added = true\\n00855| elseif part.type == 'tool' then\\n00856| M._format_tool(output, part)\\n00857| content_added = true\\n00858| elseif part.type == 'patch' and part.hash then\\n00859| M._format_patch(output, part)\\n00860| content_added = true\\n00861| end\\n00862| end\\n00863| \\n00864| if content_added then\\n00865| output:add_empty_line()\\n00866| end\\n00867| \\n00868| if is_last_part and role == 'assistant' and message.info.error and message.info.error ~= '' then\\n00869| local error = message.info.error\\n00870| local error_message = error.data and error.data.message or vim.inspect(error)\\n00871| M._format_callout(output, 'ERROR', error_message)\\n00872| output:add_empty_line()\\n00873| end\\n00874| \\n00875| return output\\n00876| end\\n00877| \\n00878| return M\\n00879| \\n\\n(End of file - total 879 lines)\\n\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"file\",\"url\":\"file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\",\"id\":\"prt_b8e7c60a7002ybV09VDHoQQeO7\",\"filename\":\"lua/opencode/ui/formatter.lua\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"mime\":\"text/plain\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3002XHHlk77vAPApvR\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"{\\\"content\\\":[{\\\"msg\\\":\\\"expected `SessionRevertInfo` but found `SessionRevertInfo?`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l156:c68\\\"},{\\\"msg\\\":\\\"expected `integer?` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l490:c43\\\"},{\\\"msg\\\":\\\"expected `integer` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l492:c45\\\"},{\\\"msg\\\":\\\"expected `integer?` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l492:c62\\\"},{\\\"msg\\\":\\\"state.active_session may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l156:c68\\\"},{\\\"msg\\\":\\\"state.messages[#state.messages] may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l272:c74\\\"},{\\\"msg\\\":\\\"state.messages may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l272:c74\\\"},{\\\"msg\\\":\\\"Undefined field `[diag.severity]`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l435:c42\\\"},{\\\"msg\\\":\\\"Undefined field `command`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l526:c34\\\"},{\\\"msg\\\":\\\"Undefined field `command`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l527:c47\\\"},{\\\"msg\\\":\\\"Cannot assign `number` to `integer`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l493:c5\\\"}],\\\"context_type\\\":\\\"diagnostics\\\"}\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"time\":{\"updated\":1767622074603,\"created\":1767622072149}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"providerID\":\"github-copilot\",\"role\":\"assistant\",\"path\":{\"root\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"cwd\":\"/home/francis/Projects/_nvim/opencode.nvim\"},\"agent\":\"build\",\"time\":{\"created\":1767622074609},\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"mode\":\"build\",\"modelID\":\"gpt-4.1\",\"id\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"parentID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"cost\":0,\"tokens\":{\"output\":0,\"reasoning\":0,\"input\":0,\"cache\":{\"write\":0,\"read\":0}}}},\"type\":\"message.updated\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"created\":1767622074530},\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"summary\":{\"diffs\":[]}}},\"type\":\"message.updated\"},{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"updated\":1767622074670,\"created\":1767622072149},\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"summary\":{\"deletions\":0,\"additions\":0,\"files\":0}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"step-start\",\"id\":\"prt_b8e7c6672001F10WAiQKbzNEtE\",\"snapshot\":\"5ba6e95774829e7f501299039b72b72dc32c6620\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"tool\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"id\":\"prt_b8e7c6686001cCV44vsFtbpF42\",\"state\":{\"status\":\"pending\",\"input\":{},\"raw\":\"\"},\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\",\"tool\":\"bash\"}},\"type\":\"message.part.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"tool\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"id\":\"prt_b8e7c6686001cCV44vsFtbpF42\",\"state\":{\"status\":\"running\",\"input\":{\"description\":\"Shows working tree status\",\"command\":\"git status\"},\"time\":{\"start\":1767622076189}},\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\",\"tool\":\"bash\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"tool\":{\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\"},\"patterns\":[\"git status\"],\"id\":\"per_b8e7c6744001DX6EZ9KHM15RLi\",\"permission\":\"bash\",\"always\":[\"git status*\"],\"metadata\":{}},\"type\":\"permission.asked\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"created\":1767622074530},\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"summary\":{\"title\":\"Running git status to list changed files\",\"diffs\":[]}}},\"type\":\"message.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"title\":\"Running git status for formatter.lua changes\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"updated\":1767622082619,\"created\":1767622072149},\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"summary\":{\"deletions\":0,\"additions\":0,\"files\":0}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"}]\n",
+ "before": "",
+ "deletions": 0,
+ "additions": 1
+ }
+ ]
+ }
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "title": "Running git status for formatter.lua changes",
+ "version": "1.1.2",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "time": { "updated": 1767622108600, "created": 1767622072149 },
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "summary": { "deletions": 0, "additions": 1, "files": 1 }
+ }
+ },
+ "type": "session.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "time": { "created": 1767622074530 },
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "role": "user",
+ "id": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "agent": "build",
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "summary": {
+ "title": "Running git status to list changed files",
+ "diffs": [
+ {
+ "file": "tests/data/permission_ask_new.json",
+ "after": "[{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"time\":{\"updated\":1767622072149,\"created\":1767622072149}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"time\":{\"created\":1767622074530}}},\"type\":\"message.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3001M2zsH9REfPdlQt\",\"text\":\"@no-trust run a git status and tell me what files are changed\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3003Ta9NcXkN0lb0lF\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"Called the Read tool with the following input: {\\\"filePath\\\":\\\"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\\\"}\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a7001d3WhKOu2vCR4Cf\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"\\n00001| local context_module = require('opencode.context')\\n00002| local icons = require('opencode.ui.icons')\\n00003| local util = require('opencode.util')\\n00004| local Output = require('opencode.ui.output')\\n00005| local state = require('opencode.state')\\n00006| local config = require('opencode.config')\\n00007| local snapshot = require('opencode.snapshot')\\n00008| local mention = require('opencode.ui.mention')\\n00009| \\n00010| local M = {}\\n00011| \\n00012| M.separator = {\\n00013| '----',\\n00014| '',\\n00015| }\\n00016| \\n00017| ---@param output Output\\n00018| ---@param part OpencodeMessagePart\\n00019| function M._format_reasoning(output, part)\\n00020| local text = vim.trim(part.text or '')\\n00021| if text == '' then\\n00022| return\\n00023| end\\n00024| \\n00025| local start_line = output:get_line_count() + 1\\n00026| \\n00027| local title = 'Reasoning'\\n00028| local time = part.time\\n00029| if time and type(time) == 'table' and time.start then\\n00030| local start_text = util.format_time(time.start) or ''\\n00031| local end_text = (time['end'] and util.format_time(time['end'])) or nil\\n00032| if end_text and end_text ~= '' then\\n00033| title = string.format('%s (%s - %s)', title, start_text, end_text)\\n00034| elseif start_text ~= '' then\\n00035| title = string.format('%s (%s)', title, start_text)\\n00036| end\\n00037| end\\n00038| \\n00039| M._format_action(output, icons.get('reasoning') .. ' ' .. title, '')\\n00040| \\n00041| if config.ui.output.tools.show_reasoning_output then\\n00042| output:add_empty_line()\\n00043| output:add_lines(vim.split(text, '\\\\n'))\\n00044| output:add_empty_line()\\n00045| end\\n00046| \\n00047| local end_line = output:get_line_count()\\n00048| if end_line - start_line > 1 then\\n00049| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1, 'OpencodeReasoningText')\\n00050| else\\n00051| output:add_extmark(start_line - 1, {\\n00052| line_hl_group = 'OpencodeReasoningText',\\n00053| } --[[@as OutputExtmark]])\\n00054| end\\n00055| end\\n00056| \\n00057| function M._handle_permission_request(output, part)\\n00058| if part.state and part.state.status == 'error' and part.state.error then\\n00059| if part.state.error:match('rejected permission') then\\n00060| state.current_permission = nil\\n00061| else\\n00062| vim.notify('Unknown part state error: ' .. part.state.error)\\n00063| end\\n00064| return\\n00065| end\\n00066| \\n00067| M._format_permission_request(output)\\n00068| end\\n00069| \\n00070| function M._format_permission_request(output)\\n00071| local keys\\n00072| \\n00073| if require('opencode.ui.ui').is_opencode_focused() then\\n00074| keys = {\\n00075| config.keymap.permission.accept,\\n00076| config.keymap.permission.accept_all,\\n00077| config.keymap.permission.deny,\\n00078| }\\n00079| else\\n00080| keys = {\\n00081| config.get_key_for_function('editor', 'permission_accept'),\\n00082| config.get_key_for_function('editor', 'permission_accept_all'),\\n00083| config.get_key_for_function('editor', 'permission_deny'),\\n00084| }\\n00085| end\\n00086| \\n00087| output:add_empty_line()\\n00088| output:add_line('> [!WARNING] Permission required to run this tool.')\\n00089| output:add_line('>')\\n00090| output:add_line(('> Accept `%s` Always `%s` Deny `%s`'):format(unpack(keys)))\\n00091| output:add_empty_line()\\n00092| end\\n00093| \\n00094| ---Calculate statistics for reverted messages and tool calls\\n00095| ---@param messages {info: MessageInfo, parts: OpencodeMessagePart[]}[] All messages in the session\\n00096| ---@param revert_index number Index of the message where revert occurred\\n00097| ---@param revert_info SessionRevertInfo Revert information\\n00098| ---@return {messages: number, tool_calls: number, files: table}\\n00099| function M._calculate_revert_stats(messages, revert_index, revert_info)\\n00100| local stats = {\\n00101| messages = 0,\\n00102| tool_calls = 0,\\n00103| files = {}, -- { [filename] = { additions = n, deletions = m } }\\n00104| }\\n00105| \\n00106| for i = revert_index, #messages do\\n00107| local msg = messages[i]\\n00108| if msg.info.role == 'user' then\\n00109| stats.messages = stats.messages + 1\\n00110| end\\n00111| if msg.parts then\\n00112| for _, part in ipairs(msg.parts) do\\n00113| if part.type == 'tool' then\\n00114| stats.tool_calls = stats.tool_calls + 1\\n00115| end\\n00116| end\\n00117| end\\n00118| end\\n00119| \\n00120| if revert_info.diff then\\n00121| local current_file = nil\\n00122| for line in revert_info.diff:gmatch('[^\\\\r\\\\n]+') do\\n00123| local file_a = line:match('^%-%-%- ([ab]/.+)')\\n00124| local file_b = line:match('^%+%+%+ ([ab]/.+)')\\n00125| if file_b then\\n00126| current_file = file_b:gsub('^[ab]/', '')\\n00127| if not stats.files[current_file] then\\n00128| stats.files[current_file] = { additions = 0, deletions = 0 }\\n00129| end\\n00130| elseif file_a then\\n00131| current_file = file_a:gsub('^[ab]/', '')\\n00132| if not stats.files[current_file] then\\n00133| stats.files[current_file] = { additions = 0, deletions = 0 }\\n00134| end\\n00135| elseif line:sub(1, 1) == '+' and not line:match('^%+%+%+') then\\n00136| if current_file then\\n00137| stats.files[current_file].additions = stats.files[current_file].additions + 1\\n00138| end\\n00139| elseif line:sub(1, 1) == '-' and not line:match('^%-%-%-') then\\n00140| if current_file then\\n00141| stats.files[current_file].deletions = stats.files[current_file].deletions + 1\\n00142| end\\n00143| end\\n00144| end\\n00145| end\\n00146| \\n00147| return stats\\n00148| end\\n00149| \\n00150| ---Format the revert callout with statistics\\n00151| ---@param session_data OpencodeMessage[] All messages in the session\\n00152| ---@param start_idx number Index of the message where revert occurred\\n00153| ---@return Output output object representing the lines, extmarks, and actions\\n00154| function M._format_revert_message(session_data, start_idx)\\n00155| local output = Output.new()\\n00156| local stats = M._calculate_revert_stats(session_data, start_idx, state.active_session.revert)\\n00157| local message_text = stats.messages == 1 and 'message' or 'messages'\\n00158| local tool_text = stats.tool_calls == 1 and 'tool call' or 'tool calls'\\n00159| \\n00160| output:add_lines(M.separator)\\n00161| output:add_line(\\n00162| string.format('> %d %s reverted, %d %s reverted', stats.messages, message_text, stats.tool_calls, tool_text)\\n00163| )\\n00164| output:add_line('>')\\n00165| output:add_line('> type `/redo` to restore.')\\n00166| output:add_empty_line()\\n00167| \\n00168| if stats.files and next(stats.files) then\\n00169| for file, fstats in pairs(stats.files) do\\n00170| local file_diff = {}\\n00171| if fstats.additions > 0 then\\n00172| table.insert(file_diff, '+' .. fstats.additions)\\n00173| end\\n00174| if fstats.deletions > 0 then\\n00175| table.insert(file_diff, '-' .. fstats.deletions)\\n00176| end\\n00177| if #file_diff > 0 then\\n00178| local line_str = string.format(icons.get('file') .. '%s: %s', file, table.concat(file_diff, ' '))\\n00179| local line_idx = output:add_line(line_str)\\n00180| local col = #(' ' .. file .. ': ')\\n00181| for _, diff in ipairs(file_diff) do\\n00182| local hl_group = diff:sub(1, 1) == '+' and 'OpencodeDiffAddText' or 'OpencodeDiffDeleteText'\\n00183| output:add_extmark(line_idx - 1, {\\n00184| virt_text = { { diff, hl_group } },\\n00185| virt_text_pos = 'inline',\\n00186| virt_text_win_col = col,\\n00187| priority = 1000,\\n00188| } --[[@as OutputExtmark]])\\n00189| col = col + #diff + 1\\n00190| end\\n00191| end\\n00192| end\\n00193| end\\n00194| return output\\n00195| end\\n00196| \\n00197| local function add_action(output, text, action_type, args, key, line)\\n00198| -- actions use api-indexing (e.g. 0 indexed)\\n00199| line = (line or output:get_line_count()) - 1\\n00200| output:add_action({\\n00201| text = text,\\n00202| type = action_type,\\n00203| args = args,\\n00204| key = key,\\n00205| display_line = line,\\n00206| range = { from = line, to = line },\\n00207| })\\n00208| end\\n00209| \\n00210| ---@param output Output Output object to write to\\n00211| ---@param part OpencodeMessagePart\\n00212| function M._format_patch(output, part)\\n00213| if not part.hash then\\n00214| return\\n00215| end\\n00216| \\n00217| local restore_points = snapshot.get_restore_points_by_parent(part.hash) or {}\\n00218| M._format_action(output, icons.get('snapshot') .. ' Created Snapshot', vim.trim(part.hash:sub(1, 8)))\\n00219| \\n00220| -- Anchor all snapshot-level actions to the snapshot header line\\n00221| add_action(output, '[R]evert file', 'diff_revert_selected_file', { part.hash }, 'R')\\n00222| add_action(output, 'Revert [A]ll', 'diff_revert_all', { part.hash }, 'A')\\n00223| add_action(output, '[D]iff', 'diff_open', { part.hash }, 'D')\\n00224| \\n00225| if #restore_points > 0 then\\n00226| for _, restore_point in ipairs(restore_points) do\\n00227| output:add_line(\\n00228| string.format(\\n00229| ' %s Restore point `%s` - %s ',\\n00230| icons.get('restore_point'),\\n00231| vim.trim(restore_point.id:sub(1, 8)),\\n00232| util.format_time(restore_point.created_at)\\n00233| )\\n00234| )\\n00235| add_action(output, 'Restore [A]ll', 'diff_restore_snapshot_all', { restore_point.id }, 'A')\\n00236| add_action(output, '[R]estore file', 'diff_restore_snapshot_file', { restore_point.id }, 'R')\\n00237| end\\n00238| end\\n00239| end\\n00240| \\n00241| ---@param output Output Output object to write to\\n00242| ---@param message MessageInfo\\n00243| function M._format_error(output, message)\\n00244| output:add_empty_line()\\n00245| M._format_callout(output, 'ERROR', vim.inspect(message.error))\\n00246| end\\n00247| \\n00248| ---@param message OpencodeMessage\\n00249| ---@return Output\\n00250| function M.format_message_header(message)\\n00251| local output = Output.new()\\n00252| \\n00253| output:add_lines(M.separator)\\n00254| local role = message.info.role or 'unknown'\\n00255| local icon = message.info.role == 'user' and icons.get('header_user') or icons.get('header_assistant')\\n00256| \\n00257| local time = message.info.time and message.info.time.created or nil\\n00258| local time_text = (time and ' (' .. util.format_time(time) .. ')' or '')\\n00259| local role_hl = 'OpencodeMessageRole' .. role:sub(1, 1):upper() .. role:sub(2)\\n00260| local model_text = message.info.modelID and ' ' .. message.info.modelID or ''\\n00261| \\n00262| local debug_text = config.debug.show_ids and ' [' .. message.info.id .. ']' or ''\\n00263| \\n00264| local display_name\\n00265| if role == 'assistant' then\\n00266| local mode = message.info.mode\\n00267| if mode and mode ~= '' then\\n00268| display_name = mode:upper()\\n00269| else\\n00270| -- For the most recent assistant message, show current_mode if mode is missing\\n00271| -- This handles new messages that haven't been stamped yet\\n00272| local is_last_message = #state.messages == 0 or message.info.id == state.messages[#state.messages].info.id\\n00273| if is_last_message and state.current_mode and state.current_mode ~= '' then\\n00274| display_name = state.current_mode:upper()\\n00275| else\\n00276| display_name = 'ASSISTANT'\\n00277| end\\n00278| end\\n00279| else\\n00280| display_name = role:upper()\\n00281| end\\n00282| \\n00283| output:add_extmark(output:get_line_count() - 1, {\\n00284| virt_text = {\\n00285| { icon, role_hl },\\n00286| { ' ' },\\n00287| { display_name, role_hl },\\n00288| { model_text, 'OpencodeHint' },\\n00289| { time_text, 'OpencodeHint' },\\n00290| { debug_text, 'OpencodeHint' },\\n00291| },\\n00292| virt_text_win_col = -3,\\n00293| priority = 10,\\n00294| } --[[@as OutputExtmark]])\\n00295| \\n00296| -- Only want to show the error if we have no parts. If we have parts, they'll\\n00297| -- handle rendering the error\\n00298| if\\n00299| role == 'assistant'\\n00300| and message.info.error\\n00301| and message.info.error ~= ''\\n00302| and (not message.parts or #message.parts == 0)\\n00303| then\\n00304| local error = message.info.error\\n00305| local error_message = error.data and error.data.message or vim.inspect(error)\\n00306| \\n00307| output:add_line('')\\n00308| M._format_callout(output, 'ERROR', error_message)\\n00309| end\\n00310| \\n00311| output:add_line('')\\n00312| return output\\n00313| end\\n00314| \\n00315| ---@param output Output Output object to write to\\n00316| ---@param callout string Callout type (e.g., 'ERROR', 'TODO')\\n00317| ---@param text string Callout text content\\n00318| ---@param title? string Optional title for the callout\\n00319| function M._format_callout(output, callout, text, title)\\n00320| title = title and title .. ' ' or ''\\n00321| local win_width = (state.windows and state.windows.output_win and vim.api.nvim_win_is_valid(state.windows.output_win))\\n00322| and vim.api.nvim_win_get_width(state.windows.output_win)\\n00323| or config.ui.window_width\\n00324| or 80\\n00325| if #text > win_width - 4 then\\n00326| local ok, substituted = pcall(vim.fn.substitute, text, '\\\\v(.{' .. (win_width - 8) .. '})', '\\\\1\\\\n', 'g')\\n00327| text = ok and substituted or text\\n00328| end\\n00329| \\n00330| -- Trim off any trailing newlines so there isn't an extra line in the\\n00331| -- extmarks section\\n00332| local lines = vim.split(text:gsub('\\\\n$', ''), '\\\\n')\\n00333| if #lines == 1 and title == '' then\\n00334| output:add_line('> [!' .. callout .. '] ' .. lines[1])\\n00335| else\\n00336| output:add_line('> [!' .. callout .. ']' .. title)\\n00337| output:add_line('>')\\n00338| output:add_lines(lines, '> ')\\n00339| end\\n00340| end\\n00341| \\n00342| ---@param output Output Output object to write to\\n00343| ---@param text string\\n00344| ---@param message? OpencodeMessage Optional message object to extract mentions from\\n00345| function M._format_user_prompt(output, text, message)\\n00346| local start_line = output:get_line_count()\\n00347| \\n00348| output:add_lines(vim.split(text, '\\\\n'))\\n00349| \\n00350| local end_line = output:get_line_count()\\n00351| \\n00352| local end_line_extmark_offset = 0\\n00353| \\n00354| local mentions = {}\\n00355| if message and message.parts then\\n00356| -- message.parts will only be filled out on a re-render\\n00357| -- we need to collect the mentions here\\n00358| for _, part in ipairs(message.parts) do\\n00359| if part.type == 'file' then\\n00360| -- we're rerendering this part and we have files, the space after the user prompt\\n00361| -- also needs an extmark\\n00362| end_line_extmark_offset = 1\\n00363| if part.source and part.source.text then\\n00364| table.insert(mentions, part.source.text)\\n00365| end\\n00366| elseif part.type == 'agent' then\\n00367| if part.source then\\n00368| table.insert(mentions, part.source)\\n00369| end\\n00370| end\\n00371| end\\n00372| end\\n00373| \\n00374| if #mentions > 0 then\\n00375| mention.highlight_mentions_in_output(output, text, mentions, start_line)\\n00376| end\\n00377| \\n00378| M._add_vertical_border(output, start_line, end_line + end_line_extmark_offset, 'OpencodeMessageRoleUser', -3)\\n00379| end\\n00380| \\n00381| ---@param output Output Output object to write to\\n00382| ---@param part OpencodeMessagePart\\n00383| function M._format_selection_context(output, part)\\n00384| local json = context_module.decode_json_context(part.text or '', 'selection')\\n00385| if not json then\\n00386| return\\n00387| end\\n00388| local start_line = output:get_line_count()\\n00389| output:add_lines(vim.split(json.content or '', '\\\\n'))\\n00390| output:add_empty_line()\\n00391| \\n00392| local end_line = output:get_line_count()\\n00393| \\n00394| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00395| end\\n00396| \\n00397| ---@param output Output Output object to write to\\n00398| ---@param part OpencodeMessagePart\\n00399| function M._format_cursor_data_context(output, part)\\n00400| local json = context_module.decode_json_context(part.text or '', 'cursor-data')\\n00401| if not json then\\n00402| return\\n00403| end\\n00404| local start_line = output:get_line_count()\\n00405| output:add_line('Line ' .. json.line .. ':')\\n00406| output:add_lines(vim.split(json.line_content or '', '\\\\n'))\\n00407| output:add_empty_line()\\n00408| \\n00409| local end_line = output:get_line_count()\\n00410| \\n00411| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00412| end\\n00413| \\n00414| ---@param output Output Output object to write to\\n00415| ---@param part OpencodeMessagePart\\n00416| function M._format_diagnostics_context(output, part)\\n00417| local json = context_module.decode_json_context(part.text or '', 'diagnostics')\\n00418| if not json then\\n00419| return\\n00420| end\\n00421| local start_line = output:get_line_count()\\n00422| local diagnostics = json.content --[[@as OpencodeDiagnostic[] ]]\\n00423| if not diagnostics or type(diagnostics) ~= 'table' or #diagnostics == 0 then\\n00424| return\\n00425| end\\n00426| \\n00427| local diagnostics_count = { error = 0, warn = 0, info = 0 }\\n00428| local diagnostics_icons = {\\n00429| error = icons.get('error'),\\n00430| warn = icons.get('warning'),\\n00431| info = icons.get('info'),\\n00432| }\\n00433| \\n00434| for _, diag in ipairs(diagnostics) do\\n00435| local name = vim.diagnostic.severity[diag.severity]:lower()\\n00436| diagnostics_count[name] = diagnostics_count[name] + 1\\n00437| end\\n00438| \\n00439| local diag_line = '**Diagnostics:**'\\n00440| for name, count in pairs(diagnostics_count) do\\n00441| if count > 0 then\\n00442| diag_line = diag_line .. (string.format(' %s(%d)', diagnostics_icons[name], count))\\n00443| end\\n00444| end\\n00445| output:add_line(diag_line)\\n00446| output:add_empty_line()\\n00447| local end_line = output:get_line_count()\\n00448| \\n00449| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\\n00450| end\\n00451| \\n00452| ---Format and display the file path in the context\\n00453| ---@param output Output Output object to write to\\n00454| ---@param path string|nil File path\\n00455| function M._format_context_file(output, path)\\n00456| if not path or path == '' then\\n00457| return\\n00458| end\\n00459| local cwd = vim.fn.getcwd()\\n00460| if vim.startswith(path, cwd) then\\n00461| path = path:sub(#cwd + 2)\\n00462| end\\n00463| return output:add_line(string.format('[%s](%s)', path, path))\\n00464| end\\n00465| \\n00466| ---@param output Output Output object to write to\\n00467| ---@param text string\\n00468| function M._format_assistant_message(output, text)\\n00469| local reference_picker = require('opencode.ui.reference_picker')\\n00470| local references = reference_picker.parse_references(text, '')\\n00471| \\n00472| -- If no references, just add the text as-is\\n00473| if #references == 0 then\\n00474| output:add_lines(vim.split(text, '\\\\n'))\\n00475| return\\n00476| end\\n00477| \\n00478| -- Sort references by match_start position (ascending)\\n00479| table.sort(references, function(a, b)\\n00480| return a.match_start < b.match_start\\n00481| end)\\n00482| \\n00483| -- Build a new text with icons inserted before each reference\\n00484| local result = ''\\n00485| local last_pos = 1\\n00486| local ref_icon = icons.get('reference')\\n00487| \\n00488| for _, ref in ipairs(references) do\\n00489| -- Add text before this reference\\n00490| result = result .. text:sub(last_pos, ref.match_start - 1)\\n00491| -- Add the icon and the reference\\n00492| result = result .. ref_icon .. text:sub(ref.match_start, ref.match_end)\\n00493| last_pos = ref.match_end + 1\\n00494| end\\n00495| \\n00496| -- Add any remaining text after the last reference\\n00497| if last_pos <= #text then\\n00498| result = result .. text:sub(last_pos)\\n00499| end\\n00500| \\n00501| output:add_lines(vim.split(result, '\\\\n'))\\n00502| end\\n00503| \\n00504| ---@param output Output Output object to write to\\n00505| ---@param tool_type string Tool type (e.g., 'run', 'read', 'edit', etc.)\\n00506| ---@param value string Value associated with the action (e.g., filename, command)\\n00507| function M._format_action(output, tool_type, value)\\n00508| if not tool_type or not value then\\n00509| return\\n00510| end\\n00511| local line = string.format('**%s** %s', tool_type, value and #value > 0 and ('`' .. value .. '`') or '')\\n00512| \\n00513| output:add_line(line)\\n00514| end\\n00515| \\n00516| ---@param output Output Output object to write to\\n00517| ---@param input BashToolInput data for the tool\\n00518| ---@param metadata BashToolMetadata Metadata for the tool use\\n00519| function M._format_bash_tool(output, input, metadata)\\n00520| M._format_action(output, icons.get('run') .. ' run', input and input.description)\\n00521| \\n00522| if not config.ui.output.tools.show_output then\\n00523| return\\n00524| end\\n00525| \\n00526| if metadata.output or metadata.command or input.command then\\n00527| local command = input.command or metadata.command or ''\\n00528| local command_output = metadata.output and metadata.output ~= '' and ('\\\\n' .. metadata.output) or ''\\n00529| M._format_code(output, vim.split('> ' .. command .. '\\\\n' .. command_output, '\\\\n'), 'bash')\\n00530| end\\n00531| end\\n00532| \\n00533| ---@param output Output Output object to write to\\n00534| ---@param tool_type string Tool type (e.g., 'read', 'edit', 'write')\\n00535| ---@param input FileToolInput data for the tool\\n00536| ---@param metadata FileToolMetadata Metadata for the tool use\\n00537| function M._format_file_tool(output, tool_type, input, metadata)\\n00538| local file_name = input and vim.fn.fnamemodify(input.filePath, ':t') or ''\\n00539| local file_type = input and util.get_markdown_filetype(input.filePath) or ''\\n00540| local tool_action_icons = { read = icons.get('read'), edit = icons.get('edit'), write = icons.get('write') }\\n00541| \\n00542| M._format_action(output, tool_action_icons[tool_type] .. ' ' .. tool_type, file_name)\\n00543| \\n00544| if not config.ui.output.tools.show_output then\\n00545| return\\n00546| end\\n00547| \\n00548| if tool_type == 'edit' and metadata.diff then\\n00549| M._format_diff(output, metadata.diff, file_type)\\n00550| elseif tool_type == 'write' and input and input.content then\\n00551| M._format_code(output, vim.split(input.content, '\\\\n'), file_type)\\n00552| end\\n00553| end\\n00554| \\n00555| ---@param output Output Output object to write to\\n00556| ---@param title string\\n00557| ---@param input TodoToolInput\\n00558| function M._format_todo_tool(output, title, input)\\n00559| M._format_action(output, icons.get('plan') .. ' plan', (title or ''))\\n00560| if not config.ui.output.tools.show_output then\\n00561| return\\n00562| end\\n00563| \\n00564| local todos = input and input.todos or {}\\n00565| \\n00566| for _, item in ipairs(todos) do\\n00567| local statuses = { in_progress = '-', completed = 'x', pending = ' ' }\\n00568| output:add_line(string.format('- [%s] %s ', statuses[item.status], item.content))\\n00569| end\\n00570| end\\n00571| \\n00572| ---@param output Output Output object to write to\\n00573| ---@param input GlobToolInput data for the tool\\n00574| ---@param metadata GlobToolMetadata Metadata for the tool use\\n00575| function M._format_glob_tool(output, input, metadata)\\n00576| M._format_action(output, icons.get('search') .. ' glob', input and input.pattern)\\n00577| if not config.ui.output.tools.show_output then\\n00578| return\\n00579| end\\n00580| local prefix = metadata.truncated and ' more than' or ''\\n00581| output:add_line(string.format('Found%s `%d` file(s):', prefix, metadata.count or 0))\\n00582| end\\n00583| \\n00584| ---@param output Output Output object to write to\\n00585| ---@param input GrepToolInput data for the tool\\n00586| ---@param metadata GrepToolMetadata Metadata for the tool use\\n00587| function M._format_grep_tool(output, input, metadata)\\n00588| input = input or { path = '', include = '', pattern = '' }\\n00589| \\n00590| local grep_str = string.format('%s` `%s', (input.path or input.include) or '', input.pattern or '')\\n00591| \\n00592| M._format_action(output, icons.get('search') .. ' grep', grep_str)\\n00593| if not config.ui.output.tools.show_output then\\n00594| return\\n00595| end\\n00596| local prefix = metadata.truncated and ' more than' or ''\\n00597| output:add_line(\\n00598| string.format('Found%s `%d` match' .. (metadata.matches ~= 1 and 'es' or ''), prefix, metadata.matches or 0)\\n00599| )\\n00600| end\\n00601| \\n00602| ---@param output Output Output object to write to\\n00603| ---@param input WebFetchToolInput data for the tool\\n00604| function M._format_webfetch_tool(output, input)\\n00605| M._format_action(output, icons.get('web') .. ' fetch', input and input.url)\\n00606| end\\n00607| \\n00608| ---@param output Output Output object to write to\\n00609| ---@param input ListToolInput\\n00610| ---@param metadata ListToolMetadata\\n00611| ---@param tool_output string\\n00612| function M._format_list_tool(output, input, metadata, tool_output)\\n00613| M._format_action(output, icons.get('list') .. ' list', input and input.path or '')\\n00614| if not config.ui.output.tools.show_output then\\n00615| return\\n00616| end\\n00617| local lines = vim.split(vim.trim(tool_output or ''), '\\\\n')\\n00618| if #lines < 1 or metadata.count == 0 then\\n00619| output:add_line('No files found.')\\n00620| return\\n00621| end\\n00622| if #lines > 1 then\\n00623| output:add_line('Files:')\\n00624| for i = 2, #lines do\\n00625| local file = vim.trim(lines[i])\\n00626| if file ~= '' then\\n00627| output:add_line(' • ' .. file)\\n00628| end\\n00629| end\\n00630| end\\n00631| if metadata.truncated then\\n00632| output:add_line(string.format('Results truncated, showing first %d files', metadata.count or '?'))\\n00633| end\\n00634| end\\n00635| \\n00636| ---@param output Output Output object to write to\\n00637| ---@param part OpencodeMessagePart\\n00638| function M._format_tool(output, part)\\n00639| local tool = part.tool\\n00640| if not tool or not part.state then\\n00641| return\\n00642| end\\n00643| \\n00644| local start_line = output:get_line_count() + 1\\n00645| local input = part.state.input or {}\\n00646| local metadata = part.state.metadata or {}\\n00647| local tool_output = part.state.output or ''\\n00648| \\n00649| if state.current_permission and state.current_permission.messageID == part.messageID then\\n00650| metadata = state.current_permission.metadata or metadata\\n00651| end\\n00652| \\n00653| if tool == 'bash' then\\n00654| M._format_bash_tool(output, input --[[@as BashToolInput]], metadata --[[@as BashToolMetadata]])\\n00655| elseif tool == 'read' or tool == 'edit' or tool == 'write' then\\n00656| M._format_file_tool(output, tool, input --[[@as FileToolInput]], metadata --[[@as FileToolMetadata]])\\n00657| elseif tool == 'todowrite' then\\n00658| M._format_todo_tool(output, part.state.title, input --[[@as TodoToolInput]])\\n00659| elseif tool == 'glob' then\\n00660| M._format_glob_tool(output, input --[[@as GlobToolInput]], metadata --[[@as GlobToolMetadata]])\\n00661| elseif tool == 'list' then\\n00662| M._format_list_tool(output, input --[[@as ListToolInput]], metadata --[[@as ListToolMetadata]], tool_output)\\n00663| elseif tool == 'grep' then\\n00664| M._format_grep_tool(output, input --[[@as GrepToolInput]], metadata --[[@as GrepToolMetadata]])\\n00665| elseif tool == 'webfetch' then\\n00666| M._format_webfetch_tool(output, input --[[@as WebFetchToolInput]])\\n00667| elseif tool == 'task' then\\n00668| M._format_task_tool(output, input --[[@as TaskToolInput]], metadata --[[@as TaskToolMetadata]], tool_output)\\n00669| else\\n00670| M._format_action(output, icons.get('tool') .. ' tool', tool)\\n00671| end\\n00672| \\n00673| if part.state.status == 'error' and part.state.error then\\n00674| output:add_line('')\\n00675| M._format_callout(output, 'ERROR', part.state.error)\\n00676| ---@diagnostic disable-next-line: undefined-field\\n00677| elseif part.state.input and part.state.input.error then\\n00678| output:add_line('')\\n00679| ---I'm not sure about the type with state.input.error\\n00680| ---@diagnostic disable-next-line: undefined-field\\n00681| M._format_callout(output, 'ERROR', part.state.input.error)\\n00682| end\\n00683| \\n00684| if\\n00685| state.current_permission\\n00686| and (\\n00687| (\\n00688| state.current_permission.tool\\n00689| and state.current_permission.tool.callID == part.callID\\n00690| and state.current_permission.tool.messageID == part.messageID\\n00691| )\\n00692| ---@TODO this is for backward compatibility, remove later\\n00693| or (state.current_permission.messageID == part.messageID and state.current_permission.callID == part.callID)\\n00694| )\\n00695| then\\n00696| M._handle_permission_request(output, part)\\n00697| end\\n00698| \\n00699| local end_line = output:get_line_count()\\n00700| if end_line - start_line > 1 then\\n00701| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1)\\n00702| end\\n00703| end\\n00704| \\n00705| ---@param output Output Output object to write to\\n00706| ---@param input TaskToolInput data for the tool\\n00707| ---@param metadata TaskToolMetadata Metadata for the tool use\\n00708| ---@param tool_output string\\n00709| function M._format_task_tool(output, input, metadata, tool_output)\\n00710| local start_line = output:get_line_count() + 1\\n00711| M._format_action(output, icons.get('task') .. ' task', input and input.description)\\n00712| \\n00713| if config.ui.output.tools.show_output then\\n00714| if tool_output and tool_output ~= '' then\\n00715| output:add_empty_line()\\n00716| output:add_lines(vim.split(tool_output, '\\\\n'))\\n00717| output:add_empty_line()\\n00718| end\\n00719| \\n00720| if metadata.summary and type(metadata.summary) == 'table' then\\n00721| for _, sub_part in ipairs(metadata.summary) do\\n00722| if sub_part.type == 'tool' and sub_part.tool then\\n00723| M._format_tool(output, sub_part)\\n00724| end\\n00725| end\\n00726| end\\n00727| end\\n00728| \\n00729| local end_line = output:get_line_count()\\n00730| output:add_action({\\n00731| text = '[S]elect Child Session',\\n00732| type = 'select_child_session',\\n00733| args = {},\\n00734| key = 'S',\\n00735| display_line = start_line - 1,\\n00736| range = { from = start_line, to = end_line },\\n00737| })\\n00738| end\\n00739| \\n00740| ---@param output Output Output object to write to\\n00741| ---@param lines string[]\\n00742| ---@param language string\\n00743| function M._format_code(output, lines, language)\\n00744| output:add_empty_line()\\n00745| --- NOTE: use longer code fence because lines could contain ```\\n00746| output:add_line('`````' .. (language or ''))\\n00747| output:add_lines(util.sanitize_lines(lines))\\n00748| output:add_line('`````')\\n00749| end\\n00750| \\n00751| ---@param output Output Output object to write to\\n00752| ---@param code string\\n00753| ---@param file_type string\\n00754| function M._format_diff(output, code, file_type)\\n00755| output:add_empty_line()\\n00756| \\n00757| --- NOTE: use longer code fence because code could contain ```\\n00758| output:add_line('`````' .. file_type)\\n00759| local lines = vim.split(code, '\\\\n')\\n00760| if #lines > 5 then\\n00761| lines = vim.list_slice(lines, 6)\\n00762| end\\n00763| \\n00764| for _, line in ipairs(lines) do\\n00765| local first_char = line:sub(1, 1)\\n00766| if first_char == '+' or first_char == '-' then\\n00767| local hl_group = first_char == '+' and 'OpencodeDiffAdd' or 'OpencodeDiffDelete'\\n00768| output:add_line(' ' .. line:sub(2))\\n00769| local line_idx = output:get_line_count()\\n00770| output:add_extmark(line_idx - 1, function()\\n00771| return {\\n00772| end_col = 0,\\n00773| end_row = line_idx,\\n00774| virt_text = { { first_char, hl_group } },\\n00775| hl_group = hl_group,\\n00776| hl_eol = true,\\n00777| priority = 5000,\\n00778| right_gravity = true,\\n00779| end_right_gravity = false,\\n00780| virt_text_hide = false,\\n00781| virt_text_pos = 'overlay',\\n00782| virt_text_repeat_linebreak = false,\\n00783| }\\n00784| end)\\n00785| else\\n00786| output:add_line(line)\\n00787| end\\n00788| end\\n00789| output:add_line('`````')\\n00790| end\\n00791| \\n00792| ---@param output Output Output object to write to\\n00793| ---@param start_line number\\n00794| ---@param end_line number\\n00795| ---@param hl_group string Highlight group for the border character\\n00796| ---@param win_col number\\n00797| ---@param text_hl_group? string Optional highlight group for the background/foreground of text lines\\n00798| function M._add_vertical_border(output, start_line, end_line, hl_group, win_col, text_hl_group)\\n00799| for line = start_line, end_line do\\n00800| local extmark_opts = {\\n00801| virt_text = { { require('opencode.ui.icons').get('border'), hl_group } },\\n00802| virt_text_pos = 'overlay',\\n00803| virt_text_win_col = win_col,\\n00804| virt_text_repeat_linebreak = true,\\n00805| }\\n00806| \\n00807| -- Add line highlight if text_hl_group is provided\\n00808| if text_hl_group then\\n00809| extmark_opts.line_hl_group = text_hl_group\\n00810| end\\n00811| \\n00812| output:add_extmark(line - 1, extmark_opts --[[@as OutputExtmark]])\\n00813| end\\n00814| end\\n00815| \\n00816| ---Formats a single message part and returns the resulting output object\\n00817| ---@param part OpencodeMessagePart The part to format\\n00818| ---@param message? OpencodeMessage Optional message object to extract role and mentions from\\n00819| ---@param is_last_part? boolean Whether this is the last part in the message, used to show an error if there is one\\n00820| ---@return Output\\n00821| function M.format_part(part, message, is_last_part)\\n00822| local output = Output.new()\\n00823| \\n00824| if not message or not message.info or not message.info.role then\\n00825| return output\\n00826| end\\n00827| \\n00828| local content_added = false\\n00829| local role = message.info.role\\n00830| \\n00831| if role == 'user' then\\n00832| if part.type == 'text' and part.text then\\n00833| if part.synthetic == true then\\n00834| M._format_selection_context(output, part)\\n00835| M._format_cursor_data_context(output, part)\\n00836| M._format_diagnostics_context(output, part)\\n00837| else\\n00838| M._format_user_prompt(output, vim.trim(part.text), message)\\n00839| content_added = true\\n00840| end\\n00841| elseif part.type == 'file' then\\n00842| local file_line = M._format_context_file(output, part.filename)\\n00843| if file_line then\\n00844| M._add_vertical_border(output, file_line - 1, file_line, 'OpencodeMessageRoleUser', -3)\\n00845| content_added = true\\n00846| end\\n00847| end\\n00848| elseif role == 'assistant' then\\n00849| if part.type == 'text' and part.text then\\n00850| M._format_assistant_message(output, vim.trim(part.text))\\n00851| content_added = true\\n00852| elseif part.type == 'reasoning' and part.text then\\n00853| M._format_reasoning(output, part)\\n00854| content_added = true\\n00855| elseif part.type == 'tool' then\\n00856| M._format_tool(output, part)\\n00857| content_added = true\\n00858| elseif part.type == 'patch' and part.hash then\\n00859| M._format_patch(output, part)\\n00860| content_added = true\\n00861| end\\n00862| end\\n00863| \\n00864| if content_added then\\n00865| output:add_empty_line()\\n00866| end\\n00867| \\n00868| if is_last_part and role == 'assistant' and message.info.error and message.info.error ~= '' then\\n00869| local error = message.info.error\\n00870| local error_message = error.data and error.data.message or vim.inspect(error)\\n00871| M._format_callout(output, 'ERROR', error_message)\\n00872| output:add_empty_line()\\n00873| end\\n00874| \\n00875| return output\\n00876| end\\n00877| \\n00878| return M\\n00879| \\n\\n(End of file - total 879 lines)\\n\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"file\",\"url\":\"file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\",\"id\":\"prt_b8e7c60a7002ybV09VDHoQQeO7\",\"filename\":\"lua/opencode/ui/formatter.lua\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"mime\":\"text/plain\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"text\",\"id\":\"prt_b8e7c60a3002XHHlk77vAPApvR\",\"messageID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"text\":\"{\\\"content\\\":[{\\\"msg\\\":\\\"expected `SessionRevertInfo` but found `SessionRevertInfo?`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l156:c68\\\"},{\\\"msg\\\":\\\"expected `integer?` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l490:c43\\\"},{\\\"msg\\\":\\\"expected `integer` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l492:c45\\\"},{\\\"msg\\\":\\\"expected `integer?` but found `number`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l492:c62\\\"},{\\\"msg\\\":\\\"state.active_session may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l156:c68\\\"},{\\\"msg\\\":\\\"state.messages[#state.messages] may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l272:c74\\\"},{\\\"msg\\\":\\\"state.messages may be nil\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l272:c74\\\"},{\\\"msg\\\":\\\"Undefined field `[diag.severity]`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l435:c42\\\"},{\\\"msg\\\":\\\"Undefined field `command`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l526:c34\\\"},{\\\"msg\\\":\\\"Undefined field `command`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l527:c47\\\"},{\\\"msg\\\":\\\"Cannot assign `number` to `integer`.\\\",\\\"severity\\\":2,\\\"pos\\\":\\\"l493:c5\\\"}],\\\"context_type\\\":\\\"diagnostics\\\"}\",\"synthetic\":true}},\"type\":\"message.part.updated\"},{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"time\":{\"updated\":1767622074603,\"created\":1767622072149}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"providerID\":\"github-copilot\",\"role\":\"assistant\",\"path\":{\"root\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"cwd\":\"/home/francis/Projects/_nvim/opencode.nvim\"},\"agent\":\"build\",\"time\":{\"created\":1767622074609},\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"mode\":\"build\",\"modelID\":\"gpt-4.1\",\"id\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"parentID\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"cost\":0,\"tokens\":{\"output\":0,\"reasoning\":0,\"input\":0,\"cache\":{\"write\":0,\"read\":0}}}},\"type\":\"message.updated\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"created\":1767622074530},\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"summary\":{\"diffs\":[]}}},\"type\":\"message.updated\"},{\"properties\":{\"info\":{\"title\":\"New session - 2026-01-05T14:07:52.149Z\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"updated\":1767622074670,\"created\":1767622072149},\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"summary\":{\"deletions\":0,\"additions\":0,\"files\":0}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"step-start\",\"id\":\"prt_b8e7c6672001F10WAiQKbzNEtE\",\"snapshot\":\"5ba6e95774829e7f501299039b72b72dc32c6620\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"tool\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"id\":\"prt_b8e7c6686001cCV44vsFtbpF42\",\"state\":{\"status\":\"pending\",\"input\":{},\"raw\":\"\"},\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\",\"tool\":\"bash\"}},\"type\":\"message.part.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"part\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"type\":\"tool\",\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"id\":\"prt_b8e7c6686001cCV44vsFtbpF42\",\"state\":{\"status\":\"running\",\"input\":{\"description\":\"Shows working tree status\",\"command\":\"git status\"},\"time\":{\"start\":1767622076189}},\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\",\"tool\":\"bash\"}},\"type\":\"message.part.updated\"},{\"properties\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"tool\":{\"messageID\":\"msg_b8e7c60f1001aEWYlAaDRXQ4aJ\",\"callID\":\"call_KAC0LdAxKEbU6HTAPH5QJfGx\"},\"patterns\":[\"git status\"],\"id\":\"per_b8e7c6744001DX6EZ9KHM15RLi\",\"permission\":\"bash\",\"always\":[\"git status*\"],\"metadata\":{}},\"type\":\"permission.asked\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"sessionID\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"created\":1767622074530},\"model\":{\"providerID\":\"github-copilot\",\"modelID\":\"gpt-4.1\"},\"role\":\"user\",\"id\":\"msg_b8e7c60a2001Kisjwk2mVB4dye\",\"agent\":\"build\",\"system\":\"# Code References\\n\\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\\n\\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\\n\\nExamples:\\n- CORRECT: \\\"The error is in `file://src/services/process.ts:712`\\\"\\n- INCORRECT: \\\"The error is in file://src/services/process.ts:712\\\"\\n- INCORRECT: \\\"The error is in src/services/process.ts:712\\\"\\n\\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\\n\",\"summary\":{\"title\":\"Running git status to list changed files\",\"diffs\":[]}}},\"type\":\"message.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"},{\"properties\":{\"info\":{\"title\":\"Running git status for formatter.lua changes\",\"version\":\"1.1.2\",\"directory\":\"/home/francis/Projects/_nvim/opencode.nvim\",\"id\":\"ses_47183a8abffeZzOLeJ3j2KV8f8\",\"time\":{\"updated\":1767622082619,\"created\":1767622072149},\"projectID\":\"29d43526f88157cd4edd071b899dd01f240b771b\",\"summary\":{\"deletions\":0,\"additions\":0,\"files\":0}}},\"type\":\"session.updated\"},{\"properties\":[],\"type\":\"custom.emit_events.finished\"}]\n",
+ "before": "",
+ "deletions": 0,
+ "additions": 1
+ }
+ ],
+ "body": "I updated the UI and event handling code by modifying `file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/event_manager.lua`, `file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua`, and `file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/renderer.lua` to improve formatting and rendering behavior. I also added `file:///home/francis/Projects/_nvim/opencode.nvim/test.lua` and `file:///home/francis/Projects/_nvim/opencode.nvim/tests/data/permission_ask_new.json` as new test/data files."
+ }
+ }
+ },
+ "type": "message.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" }
+]
diff --git a/tests/data/permission-ask-new-deny.expected.json b/tests/data/permission-ask-new-deny.expected.json
index a29f7c93..644f997a 100644
--- a/tests/data/permission-ask-new-deny.expected.json
+++ b/tests/data/permission-ask-new-deny.expected.json
@@ -1 +1,346 @@
-{"extmarks":[[1,1,0,{"ns_id":3,"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2026-01-05 14:09:08)","OpencodeHint"],[" [msg_b8e7d8222001ZAc4G1t5RfHzou]","OpencodeHint"]],"right_gravity":true,"priority":10,"virt_text_repeat_linebreak":false,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[2,2,0,{"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[3,3,0,{"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[4,4,0,{"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[5,5,0,{"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[6,8,0,{"ns_id":3,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2026-01-05 14:09:08)","OpencodeHint"],[" [msg_b8e7d823f001HX1Rr9DYE7TYBf]","OpencodeHint"]],"right_gravity":true,"priority":10,"virt_text_repeat_linebreak":false,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[7,10,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[8,11,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[9,12,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[10,13,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[11,14,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[12,15,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[13,16,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[14,17,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}]],"timestamp":1767622360,"lines":["----","","","@no-trust run a git status and tell me what files are changed","","[`lua/opencode/ui/formatter.lua`](lua/opencode/ui/formatter.lua)","","----","","","** run** `Shows working tree status`","","`````bash","> git status","","`````","","> [!ERROR] Error: The user rejected permission to use this specific tool call.","",""],"actions":[]}
+{
+ "actions": [],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2026-01-05 14:09:08)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_b8e7d8222001ZAc4G1t5RfHzou]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 2,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 3,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 4,
+ 4,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 5,
+ 5,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 6,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-4.1",
+ "OpencodeHint"
+ ],
+ [
+ " (2026-01-05 14:09:08)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_b8e7d823f001HX1Rr9DYE7TYBf]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 7,
+ 10,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 8,
+ 11,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 9,
+ 12,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 10,
+ 13,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 11,
+ 14,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 12,
+ 15,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 13,
+ 16,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 14,
+ 17,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "@no-trust run a git status and tell me what files are changed",
+ "",
+ "[`lua/opencode/ui/formatter.lua`](lua/opencode/ui/formatter.lua)",
+ "",
+ "----",
+ "",
+ "",
+ "** run** `Shows working tree status`",
+ "",
+ "`````bash",
+ "> git status",
+ "",
+ "`````",
+ "",
+ "> [!ERROR] Error: The user rejected permission to use this specific tool call.",
+ "",
+ ""
+ ],
+ "timestamp": 1770748577
+}
\ No newline at end of file
diff --git a/tests/data/permission-ask-new-deny.json b/tests/data/permission-ask-new-deny.json
index ad97fce3..00bedda4 100644
--- a/tests/data/permission-ask-new-deny.json
+++ b/tests/data/permission-ask-new-deny.json
@@ -1 +1,391 @@
-[{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"role":"user","id":"msg_b8e7d8222001ZAc4G1t5RfHzou","agent":"build","sessionID":"ses_471829192ffebHW9UmQGzvCDMj","model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","time":{"created":1767622148643}}}},{"type":"message.part.updated","properties":{"part":{"id":"prt_b8e7d8223001xEcei9tomaINdJ","type":"text","messageID":"msg_b8e7d8222001ZAc4G1t5RfHzou","sessionID":"ses_471829192ffebHW9UmQGzvCDMj","text":"@no-trust run a git status and tell me what files are changed"}}},{"type":"message.part.updated","properties":{"part":{"id":"prt_b8e7d8223002NzjiAm7x7Zcg8b","type":"text","synthetic":true,"messageID":"msg_b8e7d8222001ZAc4G1t5RfHzou","sessionID":"ses_471829192ffebHW9UmQGzvCDMj","text":"Called the Read tool with the following input: {\"filePath\":\"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\"}"}}},{"type":"message.part.updated","properties":{"part":{"id":"prt_b8e7d82270012OhYhykY53tJuV","type":"text","synthetic":true,"messageID":"msg_b8e7d8222001ZAc4G1t5RfHzou","sessionID":"ses_471829192ffebHW9UmQGzvCDMj","text":"\n00001| local context_module = require('opencode.context')\n00002| local icons = require('opencode.ui.icons')\n00003| local util = require('opencode.util')\n00004| local Output = require('opencode.ui.output')\n00005| local state = require('opencode.state')\n00006| local config = require('opencode.config')\n00007| local snapshot = require('opencode.snapshot')\n00008| local mention = require('opencode.ui.mention')\n00009| \n00010| local M = {}\n00011| \n00012| M.separator = {\n00013| '----',\n00014| '',\n00015| }\n00016| \n00017| ---@param output Output\n00018| ---@param part OpencodeMessagePart\n00019| function M._format_reasoning(output, part)\n00020| local text = vim.trim(part.text or '')\n00021| if text == '' then\n00022| return\n00023| end\n00024| \n00025| local start_line = output:get_line_count() + 1\n00026| \n00027| local title = 'Reasoning'\n00028| local time = part.time\n00029| if time and type(time) == 'table' and time.start then\n00030| local start_text = util.format_time(time.start) or ''\n00031| local end_text = (time['end'] and util.format_time(time['end'])) or nil\n00032| if end_text and end_text ~= '' then\n00033| title = string.format('%s (%s - %s)', title, start_text, end_text)\n00034| elseif start_text ~= '' then\n00035| title = string.format('%s (%s)', title, start_text)\n00036| end\n00037| end\n00038| \n00039| M._format_action(output, icons.get('reasoning') .. ' ' .. title, '')\n00040| \n00041| if config.ui.output.tools.show_reasoning_output then\n00042| output:add_empty_line()\n00043| output:add_lines(vim.split(text, '\\n'))\n00044| output:add_empty_line()\n00045| end\n00046| \n00047| local end_line = output:get_line_count()\n00048| if end_line - start_line > 1 then\n00049| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1, 'OpencodeReasoningText')\n00050| else\n00051| output:add_extmark(start_line - 1, {\n00052| line_hl_group = 'OpencodeReasoningText',\n00053| } --[[@as OutputExtmark]])\n00054| end\n00055| end\n00056| \n00057| function M._handle_permission_request(output, part)\n00058| if part.state and part.state.status == 'error' and part.state.error then\n00059| if part.state.error:match('rejected permission') then\n00060| state.current_permission = nil\n00061| else\n00062| vim.notify('Unknown part state error: ' .. part.state.error)\n00063| end\n00064| return\n00065| end\n00066| \n00067| M._format_permission_request(output)\n00068| end\n00069| \n00070| function M._format_permission_request(output)\n00071| local keys\n00072| \n00073| if require('opencode.ui.ui').is_opencode_focused() then\n00074| keys = {\n00075| config.keymap.permission.accept,\n00076| config.keymap.permission.accept_all,\n00077| config.keymap.permission.deny,\n00078| }\n00079| else\n00080| keys = {\n00081| config.get_key_for_function('editor', 'permission_accept'),\n00082| config.get_key_for_function('editor', 'permission_accept_all'),\n00083| config.get_key_for_function('editor', 'permission_deny'),\n00084| }\n00085| end\n00086| \n00087| output:add_empty_line()\n00088| output:add_line('> [!WARNING] Permission required to run this tool.')\n00089| output:add_line('>')\n00090| output:add_line(('> Accept `%s` Always `%s` Deny `%s`'):format(unpack(keys)))\n00091| output:add_empty_line()\n00092| end\n00093| \n00094| ---Calculate statistics for reverted messages and tool calls\n00095| ---@param messages {info: MessageInfo, parts: OpencodeMessagePart[]}[] All messages in the session\n00096| ---@param revert_index number Index of the message where revert occurred\n00097| ---@param revert_info SessionRevertInfo Revert information\n00098| ---@return {messages: number, tool_calls: number, files: table}\n00099| function M._calculate_revert_stats(messages, revert_index, revert_info)\n00100| local stats = {\n00101| messages = 0,\n00102| tool_calls = 0,\n00103| files = {}, -- { [filename] = { additions = n, deletions = m } }\n00104| }\n00105| \n00106| for i = revert_index, #messages do\n00107| local msg = messages[i]\n00108| if msg.info.role == 'user' then\n00109| stats.messages = stats.messages + 1\n00110| end\n00111| if msg.parts then\n00112| for _, part in ipairs(msg.parts) do\n00113| if part.type == 'tool' then\n00114| stats.tool_calls = stats.tool_calls + 1\n00115| end\n00116| end\n00117| end\n00118| end\n00119| \n00120| if revert_info.diff then\n00121| local current_file = nil\n00122| for line in revert_info.diff:gmatch('[^\\r\\n]+') do\n00123| local file_a = line:match('^%-%-%- ([ab]/.+)')\n00124| local file_b = line:match('^%+%+%+ ([ab]/.+)')\n00125| if file_b then\n00126| current_file = file_b:gsub('^[ab]/', '')\n00127| if not stats.files[current_file] then\n00128| stats.files[current_file] = { additions = 0, deletions = 0 }\n00129| end\n00130| elseif file_a then\n00131| current_file = file_a:gsub('^[ab]/', '')\n00132| if not stats.files[current_file] then\n00133| stats.files[current_file] = { additions = 0, deletions = 0 }\n00134| end\n00135| elseif line:sub(1, 1) == '+' and not line:match('^%+%+%+') then\n00136| if current_file then\n00137| stats.files[current_file].additions = stats.files[current_file].additions + 1\n00138| end\n00139| elseif line:sub(1, 1) == '-' and not line:match('^%-%-%-') then\n00140| if current_file then\n00141| stats.files[current_file].deletions = stats.files[current_file].deletions + 1\n00142| end\n00143| end\n00144| end\n00145| end\n00146| \n00147| return stats\n00148| end\n00149| \n00150| ---Format the revert callout with statistics\n00151| ---@param session_data OpencodeMessage[] All messages in the session\n00152| ---@param start_idx number Index of the message where revert occurred\n00153| ---@return Output output object representing the lines, extmarks, and actions\n00154| function M._format_revert_message(session_data, start_idx)\n00155| local output = Output.new()\n00156| local stats = M._calculate_revert_stats(session_data, start_idx, state.active_session.revert)\n00157| local message_text = stats.messages == 1 and 'message' or 'messages'\n00158| local tool_text = stats.tool_calls == 1 and 'tool call' or 'tool calls'\n00159| \n00160| output:add_lines(M.separator)\n00161| output:add_line(\n00162| string.format('> %d %s reverted, %d %s reverted', stats.messages, message_text, stats.tool_calls, tool_text)\n00163| )\n00164| output:add_line('>')\n00165| output:add_line('> type `/redo` to restore.')\n00166| output:add_empty_line()\n00167| \n00168| if stats.files and next(stats.files) then\n00169| for file, fstats in pairs(stats.files) do\n00170| local file_diff = {}\n00171| if fstats.additions > 0 then\n00172| table.insert(file_diff, '+' .. fstats.additions)\n00173| end\n00174| if fstats.deletions > 0 then\n00175| table.insert(file_diff, '-' .. fstats.deletions)\n00176| end\n00177| if #file_diff > 0 then\n00178| local line_str = string.format(icons.get('file') .. '%s: %s', file, table.concat(file_diff, ' '))\n00179| local line_idx = output:add_line(line_str)\n00180| local col = #(' ' .. file .. ': ')\n00181| for _, diff in ipairs(file_diff) do\n00182| local hl_group = diff:sub(1, 1) == '+' and 'OpencodeDiffAddText' or 'OpencodeDiffDeleteText'\n00183| output:add_extmark(line_idx - 1, {\n00184| virt_text = { { diff, hl_group } },\n00185| virt_text_pos = 'inline',\n00186| virt_text_win_col = col,\n00187| priority = 1000,\n00188| } --[[@as OutputExtmark]])\n00189| col = col + #diff + 1\n00190| end\n00191| end\n00192| end\n00193| end\n00194| return output\n00195| end\n00196| \n00197| local function add_action(output, text, action_type, args, key, line)\n00198| -- actions use api-indexing (e.g. 0 indexed)\n00199| line = (line or output:get_line_count()) - 1\n00200| output:add_action({\n00201| text = text,\n00202| type = action_type,\n00203| args = args,\n00204| key = key,\n00205| display_line = line,\n00206| range = { from = line, to = line },\n00207| })\n00208| end\n00209| \n00210| ---@param output Output Output object to write to\n00211| ---@param part OpencodeMessagePart\n00212| function M._format_patch(output, part)\n00213| if not part.hash then\n00214| return\n00215| end\n00216| \n00217| local restore_points = snapshot.get_restore_points_by_parent(part.hash) or {}\n00218| M._format_action(output, icons.get('snapshot') .. ' Created Snapshot', vim.trim(part.hash:sub(1, 8)))\n00219| \n00220| -- Anchor all snapshot-level actions to the snapshot header line\n00221| add_action(output, '[R]evert file', 'diff_revert_selected_file', { part.hash }, 'R')\n00222| add_action(output, 'Revert [A]ll', 'diff_revert_all', { part.hash }, 'A')\n00223| add_action(output, '[D]iff', 'diff_open', { part.hash }, 'D')\n00224| \n00225| if #restore_points > 0 then\n00226| for _, restore_point in ipairs(restore_points) do\n00227| output:add_line(\n00228| string.format(\n00229| ' %s Restore point `%s` - %s ',\n00230| icons.get('restore_point'),\n00231| vim.trim(restore_point.id:sub(1, 8)),\n00232| util.format_time(restore_point.created_at)\n00233| )\n00234| )\n00235| add_action(output, 'Restore [A]ll', 'diff_restore_snapshot_all', { restore_point.id }, 'A')\n00236| add_action(output, '[R]estore file', 'diff_restore_snapshot_file', { restore_point.id }, 'R')\n00237| end\n00238| end\n00239| end\n00240| \n00241| ---@param output Output Output object to write to\n00242| ---@param message MessageInfo\n00243| function M._format_error(output, message)\n00244| output:add_empty_line()\n00245| M._format_callout(output, 'ERROR', vim.inspect(message.error))\n00246| end\n00247| \n00248| ---@param message OpencodeMessage\n00249| ---@return Output\n00250| function M.format_message_header(message)\n00251| local output = Output.new()\n00252| \n00253| output:add_lines(M.separator)\n00254| local role = message.info.role or 'unknown'\n00255| local icon = message.info.role == 'user' and icons.get('header_user') or icons.get('header_assistant')\n00256| \n00257| local time = message.info.time and message.info.time.created or nil\n00258| local time_text = (time and ' (' .. util.format_time(time) .. ')' or '')\n00259| local role_hl = 'OpencodeMessageRole' .. role:sub(1, 1):upper() .. role:sub(2)\n00260| local model_text = message.info.modelID and ' ' .. message.info.modelID or ''\n00261| \n00262| local debug_text = config.debug.show_ids and ' [' .. message.info.id .. ']' or ''\n00263| \n00264| local display_name\n00265| if role == 'assistant' then\n00266| local mode = message.info.mode\n00267| if mode and mode ~= '' then\n00268| display_name = mode:upper()\n00269| else\n00270| -- For the most recent assistant message, show current_mode if mode is missing\n00271| -- This handles new messages that haven't been stamped yet\n00272| local is_last_message = #state.messages == 0 or message.info.id == state.messages[#state.messages].info.id\n00273| if is_last_message and state.current_mode and state.current_mode ~= '' then\n00274| display_name = state.current_mode:upper()\n00275| else\n00276| display_name = 'ASSISTANT'\n00277| end\n00278| end\n00279| else\n00280| display_name = role:upper()\n00281| end\n00282| \n00283| output:add_extmark(output:get_line_count() - 1, {\n00284| virt_text = {\n00285| { icon, role_hl },\n00286| { ' ' },\n00287| { display_name, role_hl },\n00288| { model_text, 'OpencodeHint' },\n00289| { time_text, 'OpencodeHint' },\n00290| { debug_text, 'OpencodeHint' },\n00291| },\n00292| virt_text_win_col = -3,\n00293| priority = 10,\n00294| } --[[@as OutputExtmark]])\n00295| \n00296| -- Only want to show the error if we have no parts. If we have parts, they'll\n00297| -- handle rendering the error\n00298| if\n00299| role == 'assistant'\n00300| and message.info.error\n00301| and message.info.error ~= ''\n00302| and (not message.parts or #message.parts == 0)\n00303| then\n00304| local error = message.info.error\n00305| local error_message = error.data and error.data.message or vim.inspect(error)\n00306| \n00307| output:add_line('')\n00308| M._format_callout(output, 'ERROR', error_message)\n00309| end\n00310| \n00311| output:add_line('')\n00312| return output\n00313| end\n00314| \n00315| ---@param output Output Output object to write to\n00316| ---@param callout string Callout type (e.g., 'ERROR', 'TODO')\n00317| ---@param text string Callout text content\n00318| ---@param title? string Optional title for the callout\n00319| function M._format_callout(output, callout, text, title)\n00320| title = title and title .. ' ' or ''\n00321| local win_width = (state.windows and state.windows.output_win and vim.api.nvim_win_is_valid(state.windows.output_win))\n00322| and vim.api.nvim_win_get_width(state.windows.output_win)\n00323| or config.ui.window_width\n00324| or 80\n00325| if #text > win_width - 4 then\n00326| local ok, substituted = pcall(vim.fn.substitute, text, '\\v(.{' .. (win_width - 8) .. '})', '\\1\\n', 'g')\n00327| text = ok and substituted or text\n00328| end\n00329| \n00330| -- Trim off any trailing newlines so there isn't an extra line in the\n00331| -- extmarks section\n00332| local lines = vim.split(text:gsub('\\n$', ''), '\\n')\n00333| if #lines == 1 and title == '' then\n00334| output:add_line('> [!' .. callout .. '] ' .. lines[1])\n00335| else\n00336| output:add_line('> [!' .. callout .. ']' .. title)\n00337| output:add_line('>')\n00338| output:add_lines(lines, '> ')\n00339| end\n00340| end\n00341| \n00342| ---@param output Output Output object to write to\n00343| ---@param text string\n00344| ---@param message? OpencodeMessage Optional message object to extract mentions from\n00345| function M._format_user_prompt(output, text, message)\n00346| local start_line = output:get_line_count()\n00347| \n00348| output:add_lines(vim.split(text, '\\n'))\n00349| \n00350| local end_line = output:get_line_count()\n00351| \n00352| local end_line_extmark_offset = 0\n00353| \n00354| local mentions = {}\n00355| if message and message.parts then\n00356| -- message.parts will only be filled out on a re-render\n00357| -- we need to collect the mentions here\n00358| for _, part in ipairs(message.parts) do\n00359| if part.type == 'file' then\n00360| -- we're rerendering this part and we have files, the space after the user prompt\n00361| -- also needs an extmark\n00362| end_line_extmark_offset = 1\n00363| if part.source and part.source.text then\n00364| table.insert(mentions, part.source.text)\n00365| end\n00366| elseif part.type == 'agent' then\n00367| if part.source then\n00368| table.insert(mentions, part.source)\n00369| end\n00370| end\n00371| end\n00372| end\n00373| \n00374| if #mentions > 0 then\n00375| mention.highlight_mentions_in_output(output, text, mentions, start_line)\n00376| end\n00377| \n00378| M._add_vertical_border(output, start_line, end_line + end_line_extmark_offset, 'OpencodeMessageRoleUser', -3)\n00379| end\n00380| \n00381| ---@param output Output Output object to write to\n00382| ---@param part OpencodeMessagePart\n00383| function M._format_selection_context(output, part)\n00384| local json = context_module.decode_json_context(part.text or '', 'selection')\n00385| if not json then\n00386| return\n00387| end\n00388| local start_line = output:get_line_count()\n00389| output:add_lines(vim.split(json.content or '', '\\n'))\n00390| output:add_empty_line()\n00391| \n00392| local end_line = output:get_line_count()\n00393| \n00394| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00395| end\n00396| \n00397| ---@param output Output Output object to write to\n00398| ---@param part OpencodeMessagePart\n00399| function M._format_cursor_data_context(output, part)\n00400| local json = context_module.decode_json_context(part.text or '', 'cursor-data')\n00401| if not json then\n00402| return\n00403| end\n00404| local start_line = output:get_line_count()\n00405| output:add_line('Line ' .. json.line .. ':')\n00406| output:add_lines(vim.split(json.line_content or '', '\\n'))\n00407| output:add_empty_line()\n00408| \n00409| local end_line = output:get_line_count()\n00410| \n00411| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00412| end\n00413| \n00414| ---@param output Output Output object to write to\n00415| ---@param part OpencodeMessagePart\n00416| function M._format_diagnostics_context(output, part)\n00417| local json = context_module.decode_json_context(part.text or '', 'diagnostics')\n00418| if not json then\n00419| return\n00420| end\n00421| local start_line = output:get_line_count()\n00422| local diagnostics = json.content --[[@as OpencodeDiagnostic[] ]]\n00423| if not diagnostics or type(diagnostics) ~= 'table' or #diagnostics == 0 then\n00424| return\n00425| end\n00426| \n00427| local diagnostics_count = { error = 0, warn = 0, info = 0 }\n00428| local diagnostics_icons = {\n00429| error = icons.get('error'),\n00430| warn = icons.get('warning'),\n00431| info = icons.get('info'),\n00432| }\n00433| \n00434| for _, diag in ipairs(diagnostics) do\n00435| local name = vim.diagnostic.severity[diag.severity]:lower()\n00436| diagnostics_count[name] = diagnostics_count[name] + 1\n00437| end\n00438| \n00439| local diag_line = '**Diagnostics:**'\n00440| for name, count in pairs(diagnostics_count) do\n00441| if count > 0 then\n00442| diag_line = diag_line .. (string.format(' %s(%d)', diagnostics_icons[name], count))\n00443| end\n00444| end\n00445| output:add_line(diag_line)\n00446| output:add_empty_line()\n00447| local end_line = output:get_line_count()\n00448| \n00449| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00450| end\n00451| \n00452| ---Format and display the file path in the context\n00453| ---@param output Output Output object to write to\n00454| ---@param path string|nil File path\n00455| function M._format_context_file(output, path)\n00456| if not path or path == '' then\n00457| return\n00458| end\n00459| local cwd = vim.fn.getcwd()\n00460| if vim.startswith(path, cwd) then\n00461| path = path:sub(#cwd + 2)\n00462| end\n00463| return output:add_line(string.format('[%s](%s)', path, path))\n00464| end\n00465| \n00466| ---@param output Output Output object to write to\n00467| ---@param text string\n00468| function M._format_assistant_message(output, text)\n00469| local reference_picker = require('opencode.ui.reference_picker')\n00470| local references = reference_picker.parse_references(text, '')\n00471| \n00472| -- If no references, just add the text as-is\n00473| if #references == 0 then\n00474| output:add_lines(vim.split(text, '\\n'))\n00475| return\n00476| end\n00477| \n00478| -- Sort references by match_start position (ascending)\n00479| table.sort(references, function(a, b)\n00480| return a.match_start < b.match_start\n00481| end)\n00482| \n00483| -- Build a new text with icons inserted before each reference\n00484| local result = ''\n00485| local last_pos = 1\n00486| local ref_icon = icons.get('reference')\n00487| \n00488| for _, ref in ipairs(references) do\n00489| -- Add text before this reference\n00490| result = result .. text:sub(last_pos, ref.match_start - 1)\n00491| -- Add the icon and the reference\n00492| result = result .. ref_icon .. text:sub(ref.match_start, ref.match_end)\n00493| last_pos = ref.match_end + 1\n00494| end\n00495| \n00496| -- Add any remaining text after the last reference\n00497| if last_pos <= #text then\n00498| result = result .. text:sub(last_pos)\n00499| end\n00500| \n00501| output:add_lines(vim.split(result, '\\n'))\n00502| end\n00503| \n00504| ---@param output Output Output object to write to\n00505| ---@param tool_type string Tool type (e.g., 'run', 'read', 'edit', etc.)\n00506| ---@param value string Value associated with the action (e.g., filename, command)\n00507| function M._format_action(output, tool_type, value)\n00508| if not tool_type or not value then\n00509| return\n00510| end\n00511| local line = string.format('**%s** %s', tool_type, value and #value > 0 and ('`' .. value .. '`') or '')\n00512| \n00513| output:add_line(line)\n00514| end\n00515| \n00516| ---@param output Output Output object to write to\n00517| ---@param input BashToolInput data for the tool\n00518| ---@param metadata BashToolMetadata Metadata for the tool use\n00519| function M._format_bash_tool(output, input, metadata)\n00520| M._format_action(output, icons.get('run') .. ' run', input and input.description)\n00521| \n00522| if not config.ui.output.tools.show_output then\n00523| return\n00524| end\n00525| \n00526| if metadata.output or metadata.command or input.command then\n00527| local command = input.command or metadata.command or ''\n00528| local command_output = metadata.output and metadata.output ~= '' and ('\\n' .. metadata.output) or ''\n00529| M._format_code(output, vim.split('> ' .. command .. '\\n' .. command_output, '\\n'), 'bash')\n00530| end\n00531| end\n00532| \n00533| ---@param output Output Output object to write to\n00534| ---@param tool_type string Tool type (e.g., 'read', 'edit', 'write')\n00535| ---@param input FileToolInput data for the tool\n00536| ---@param metadata FileToolMetadata Metadata for the tool use\n00537| function M._format_file_tool(output, tool_type, input, metadata)\n00538| local file_name = input and vim.fn.fnamemodify(input.filePath, ':t') or ''\n00539| local file_type = input and util.get_markdown_filetype(input.filePath) or ''\n00540| local tool_action_icons = { read = icons.get('read'), edit = icons.get('edit'), write = icons.get('write') }\n00541| \n00542| M._format_action(output, tool_action_icons[tool_type] .. ' ' .. tool_type, file_name)\n00543| \n00544| if not config.ui.output.tools.show_output then\n00545| return\n00546| end\n00547| \n00548| if tool_type == 'edit' and metadata.diff then\n00549| M._format_diff(output, metadata.diff, file_type)\n00550| elseif tool_type == 'write' and input and input.content then\n00551| M._format_code(output, vim.split(input.content, '\\n'), file_type)\n00552| end\n00553| end\n00554| \n00555| ---@param output Output Output object to write to\n00556| ---@param title string\n00557| ---@param input TodoToolInput\n00558| function M._format_todo_tool(output, title, input)\n00559| M._format_action(output, icons.get('plan') .. ' plan', (title or ''))\n00560| if not config.ui.output.tools.show_output then\n00561| return\n00562| end\n00563| \n00564| local todos = input and input.todos or {}\n00565| \n00566| for _, item in ipairs(todos) do\n00567| local statuses = { in_progress = '-', completed = 'x', pending = ' ' }\n00568| output:add_line(string.format('- [%s] %s ', statuses[item.status], item.content))\n00569| end\n00570| end\n00571| \n00572| ---@param output Output Output object to write to\n00573| ---@param input GlobToolInput data for the tool\n00574| ---@param metadata GlobToolMetadata Metadata for the tool use\n00575| function M._format_glob_tool(output, input, metadata)\n00576| M._format_action(output, icons.get('search') .. ' glob', input and input.pattern)\n00577| if not config.ui.output.tools.show_output then\n00578| return\n00579| end\n00580| local prefix = metadata.truncated and ' more than' or ''\n00581| output:add_line(string.format('Found%s `%d` file(s):', prefix, metadata.count or 0))\n00582| end\n00583| \n00584| ---@param output Output Output object to write to\n00585| ---@param input GrepToolInput data for the tool\n00586| ---@param metadata GrepToolMetadata Metadata for the tool use\n00587| function M._format_grep_tool(output, input, metadata)\n00588| input = input or { path = '', include = '', pattern = '' }\n00589| \n00590| local grep_str = string.format('%s` `%s', (input.path or input.include) or '', input.pattern or '')\n00591| \n00592| M._format_action(output, icons.get('search') .. ' grep', grep_str)\n00593| if not config.ui.output.tools.show_output then\n00594| return\n00595| end\n00596| local prefix = metadata.truncated and ' more than' or ''\n00597| output:add_line(\n00598| string.format('Found%s `%d` match' .. (metadata.matches ~= 1 and 'es' or ''), prefix, metadata.matches or 0)\n00599| )\n00600| end\n00601| \n00602| ---@param output Output Output object to write to\n00603| ---@param input WebFetchToolInput data for the tool\n00604| function M._format_webfetch_tool(output, input)\n00605| M._format_action(output, icons.get('web') .. ' fetch', input and input.url)\n00606| end\n00607| \n00608| ---@param output Output Output object to write to\n00609| ---@param input ListToolInput\n00610| ---@param metadata ListToolMetadata\n00611| ---@param tool_output string\n00612| function M._format_list_tool(output, input, metadata, tool_output)\n00613| M._format_action(output, icons.get('list') .. ' list', input and input.path or '')\n00614| if not config.ui.output.tools.show_output then\n00615| return\n00616| end\n00617| local lines = vim.split(vim.trim(tool_output or ''), '\\n')\n00618| if #lines < 1 or metadata.count == 0 then\n00619| output:add_line('No files found.')\n00620| return\n00621| end\n00622| if #lines > 1 then\n00623| output:add_line('Files:')\n00624| for i = 2, #lines do\n00625| local file = vim.trim(lines[i])\n00626| if file ~= '' then\n00627| output:add_line(' • ' .. file)\n00628| end\n00629| end\n00630| end\n00631| if metadata.truncated then\n00632| output:add_line(string.format('Results truncated, showing first %d files', metadata.count or '?'))\n00633| end\n00634| end\n00635| \n00636| ---@param output Output Output object to write to\n00637| ---@param part OpencodeMessagePart\n00638| function M._format_tool(output, part)\n00639| local tool = part.tool\n00640| if not tool or not part.state then\n00641| return\n00642| end\n00643| \n00644| local start_line = output:get_line_count() + 1\n00645| local input = part.state.input or {}\n00646| local metadata = part.state.metadata or {}\n00647| local tool_output = part.state.output or ''\n00648| \n00649| if state.current_permission and state.current_permission.messageID == part.messageID then\n00650| metadata = state.current_permission.metadata or metadata\n00651| end\n00652| \n00653| if tool == 'bash' then\n00654| M._format_bash_tool(output, input --[[@as BashToolInput]], metadata --[[@as BashToolMetadata]])\n00655| elseif tool == 'read' or tool == 'edit' or tool == 'write' then\n00656| M._format_file_tool(output, tool, input --[[@as FileToolInput]], metadata --[[@as FileToolMetadata]])\n00657| elseif tool == 'todowrite' then\n00658| M._format_todo_tool(output, part.state.title, input --[[@as TodoToolInput]])\n00659| elseif tool == 'glob' then\n00660| M._format_glob_tool(output, input --[[@as GlobToolInput]], metadata --[[@as GlobToolMetadata]])\n00661| elseif tool == 'list' then\n00662| M._format_list_tool(output, input --[[@as ListToolInput]], metadata --[[@as ListToolMetadata]], tool_output)\n00663| elseif tool == 'grep' then\n00664| M._format_grep_tool(output, input --[[@as GrepToolInput]], metadata --[[@as GrepToolMetadata]])\n00665| elseif tool == 'webfetch' then\n00666| M._format_webfetch_tool(output, input --[[@as WebFetchToolInput]])\n00667| elseif tool == 'task' then\n00668| M._format_task_tool(output, input --[[@as TaskToolInput]], metadata --[[@as TaskToolMetadata]], tool_output)\n00669| else\n00670| M._format_action(output, icons.get('tool') .. ' tool', tool)\n00671| end\n00672| \n00673| if part.state.status == 'error' and part.state.error then\n00674| output:add_line('')\n00675| M._format_callout(output, 'ERROR', part.state.error)\n00676| ---@diagnostic disable-next-line: undefined-field\n00677| elseif part.state.input and part.state.input.error then\n00678| output:add_line('')\n00679| ---I'm not sure about the type with state.input.error\n00680| ---@diagnostic disable-next-line: undefined-field\n00681| M._format_callout(output, 'ERROR', part.state.input.error)\n00682| end\n00683| \n00684| if\n00685| state.current_permission\n00686| and (\n00687| (\n00688| state.current_permission.tool\n00689| and state.current_permission.tool.callID == part.callID\n00690| and state.current_permission.tool.messageID == part.messageID\n00691| )\n00692| ---@TODO this is for backward compatibility, remove later\n00693| or (state.current_permission.messageID == part.messageID and state.current_permission.callID == part.callID)\n00694| )\n00695| then\n00696| M._handle_permission_request(output, part)\n00697| end\n00698| \n00699| local end_line = output:get_line_count()\n00700| if end_line - start_line > 1 then\n00701| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1)\n00702| end\n00703| end\n00704| \n00705| ---@param output Output Output object to write to\n00706| ---@param input TaskToolInput data for the tool\n00707| ---@param metadata TaskToolMetadata Metadata for the tool use\n00708| ---@param tool_output string\n00709| function M._format_task_tool(output, input, metadata, tool_output)\n00710| local start_line = output:get_line_count() + 1\n00711| M._format_action(output, icons.get('task') .. ' task', input and input.description)\n00712| \n00713| if config.ui.output.tools.show_output then\n00714| if tool_output and tool_output ~= '' then\n00715| output:add_empty_line()\n00716| output:add_lines(vim.split(tool_output, '\\n'))\n00717| output:add_empty_line()\n00718| end\n00719| \n00720| if metadata.summary and type(metadata.summary) == 'table' then\n00721| for _, sub_part in ipairs(metadata.summary) do\n00722| if sub_part.type == 'tool' and sub_part.tool then\n00723| M._format_tool(output, sub_part)\n00724| end\n00725| end\n00726| end\n00727| end\n00728| \n00729| local end_line = output:get_line_count()\n00730| output:add_action({\n00731| text = '[S]elect Child Session',\n00732| type = 'select_child_session',\n00733| args = {},\n00734| key = 'S',\n00735| display_line = start_line - 1,\n00736| range = { from = start_line, to = end_line },\n00737| })\n00738| end\n00739| \n00740| ---@param output Output Output object to write to\n00741| ---@param lines string[]\n00742| ---@param language string\n00743| function M._format_code(output, lines, language)\n00744| output:add_empty_line()\n00745| --- NOTE: use longer code fence because lines could contain ```\n00746| output:add_line('`````' .. (language or ''))\n00747| output:add_lines(util.sanitize_lines(lines))\n00748| output:add_line('`````')\n00749| end\n00750| \n00751| ---@param output Output Output object to write to\n00752| ---@param code string\n00753| ---@param file_type string\n00754| function M._format_diff(output, code, file_type)\n00755| output:add_empty_line()\n00756| \n00757| --- NOTE: use longer code fence because code could contain ```\n00758| output:add_line('`````' .. file_type)\n00759| local lines = vim.split(code, '\\n')\n00760| if #lines > 5 then\n00761| lines = vim.list_slice(lines, 6)\n00762| end\n00763| \n00764| for _, line in ipairs(lines) do\n00765| local first_char = line:sub(1, 1)\n00766| if first_char == '+' or first_char == '-' then\n00767| local hl_group = first_char == '+' and 'OpencodeDiffAdd' or 'OpencodeDiffDelete'\n00768| output:add_line(' ' .. line:sub(2))\n00769| local line_idx = output:get_line_count()\n00770| output:add_extmark(line_idx - 1, function()\n00771| return {\n00772| end_col = 0,\n00773| end_row = line_idx,\n00774| virt_text = { { first_char, hl_group } },\n00775| hl_group = hl_group,\n00776| hl_eol = true,\n00777| priority = 5000,\n00778| right_gravity = true,\n00779| end_right_gravity = false,\n00780| virt_text_hide = false,\n00781| virt_text_pos = 'overlay',\n00782| virt_text_repeat_linebreak = false,\n00783| }\n00784| end)\n00785| else\n00786| output:add_line(line)\n00787| end\n00788| end\n00789| output:add_line('`````')\n00790| end\n00791| \n00792| ---@param output Output Output object to write to\n00793| ---@param start_line number\n00794| ---@param end_line number\n00795| ---@param hl_group string Highlight group for the border character\n00796| ---@param win_col number\n00797| ---@param text_hl_group? string Optional highlight group for the background/foreground of text lines\n00798| function M._add_vertical_border(output, start_line, end_line, hl_group, win_col, text_hl_group)\n00799| for line = start_line, end_line do\n00800| local extmark_opts = {\n00801| virt_text = { { require('opencode.ui.icons').get('border'), hl_group } },\n00802| virt_text_pos = 'overlay',\n00803| virt_text_win_col = win_col,\n00804| virt_text_repeat_linebreak = true,\n00805| }\n00806| \n00807| -- Add line highlight if text_hl_group is provided\n00808| if text_hl_group then\n00809| extmark_opts.line_hl_group = text_hl_group\n00810| end\n00811| \n00812| output:add_extmark(line - 1, extmark_opts --[[@as OutputExtmark]])\n00813| end\n00814| end\n00815| \n00816| ---Formats a single message part and returns the resulting output object\n00817| ---@param part OpencodeMessagePart The part to format\n00818| ---@param message? OpencodeMessage Optional message object to extract role and mentions from\n00819| ---@param is_last_part? boolean Whether this is the last part in the message, used to show an error if there is one\n00820| ---@return Output\n00821| function M.format_part(part, message, is_last_part)\n00822| local output = Output.new()\n00823| \n00824| if not message or not message.info or not message.info.role then\n00825| return output\n00826| end\n00827| \n00828| local content_added = false\n00829| local role = message.info.role\n00830| \n00831| if role == 'user' then\n00832| if part.type == 'text' and part.text then\n00833| if part.synthetic == true then\n00834| M._format_selection_context(output, part)\n00835| M._format_cursor_data_context(output, part)\n00836| M._format_diagnostics_context(output, part)\n00837| else\n00838| M._format_user_prompt(output, vim.trim(part.text), message)\n00839| content_added = true\n00840| end\n00841| elseif part.type == 'file' then\n00842| local file_line = M._format_context_file(output, part.filename)\n00843| if file_line then\n00844| M._add_vertical_border(output, file_line - 1, file_line, 'OpencodeMessageRoleUser', -3)\n00845| content_added = true\n00846| end\n00847| end\n00848| elseif role == 'assistant' then\n00849| if part.type == 'text' and part.text then\n00850| M._format_assistant_message(output, vim.trim(part.text))\n00851| content_added = true\n00852| elseif part.type == 'reasoning' and part.text then\n00853| M._format_reasoning(output, part)\n00854| content_added = true\n00855| elseif part.type == 'tool' then\n00856| M._format_tool(output, part)\n00857| content_added = true\n00858| elseif part.type == 'patch' and part.hash then\n00859| M._format_patch(output, part)\n00860| content_added = true\n00861| end\n00862| end\n00863| \n00864| if content_added then\n00865| output:add_empty_line()\n00866| end\n00867| \n00868| if is_last_part and role == 'assistant' and message.info.error and message.info.error ~= '' then\n00869| local error = message.info.error\n00870| local error_message = error.data and error.data.message or vim.inspect(error)\n00871| M._format_callout(output, 'ERROR', error_message)\n00872| output:add_empty_line()\n00873| end\n00874| \n00875| return output\n00876| end\n00877| \n00878| return M\n00879| \n\n(End of file - total 879 lines)\n"}}},{"type":"message.part.updated","properties":{"part":{"id":"prt_b8e7d8227002hZiHYfLznqKXjU","type":"file","url":"file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua","mime":"text/plain","messageID":"msg_b8e7d8222001ZAc4G1t5RfHzou","sessionID":"ses_471829192ffebHW9UmQGzvCDMj","filename":"lua/opencode/ui/formatter.lua"}}},{"type":"session.updated","properties":{"info":{"title":"New session - 2026-01-05T14:09:03.597Z","time":{"created":1767622143597,"updated":1767622148667},"version":"1.1.2","id":"ses_471829192ffebHW9UmQGzvCDMj","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","directory":"/home/francis/Projects/_nvim/opencode.nvim"}}},{"type":"message.updated","properties":{"info":{"parentID":"msg_b8e7d8222001ZAc4G1t5RfHzou","role":"assistant","time":{"created":1767622148672},"path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"sessionID":"ses_471829192ffebHW9UmQGzvCDMj","mode":"build","modelID":"gpt-4.1","providerID":"github-copilot","agent":"build","tokens":{"cache":{"read":0,"write":0},"output":0,"input":0,"reasoning":0},"id":"msg_b8e7d823f001HX1Rr9DYE7TYBf","cost":0}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"id":"msg_b8e7d8222001ZAc4G1t5RfHzou","role":"user","sessionID":"ses_471829192ffebHW9UmQGzvCDMj","time":{"created":1767622148643},"summary":{"diffs":[]},"model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","agent":"build"}}},{"type":"session.updated","properties":{"info":{"version":"1.1.2","time":{"created":1767622143597,"updated":1767622148771},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","summary":{"additions":0,"files":0,"deletions":0},"id":"ses_471829192ffebHW9UmQGzvCDMj","title":"New session - 2026-01-05T14:09:03.597Z","directory":"/home/francis/Projects/_nvim/opencode.nvim"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"id":"prt_b8e7d8948001TJr45cBt0IJmwi","type":"step-start","snapshot":"f28b6ec26f4d2f0f1c8fdb665276f5628facc967","messageID":"msg_b8e7d823f001HX1Rr9DYE7TYBf","sessionID":"ses_471829192ffebHW9UmQGzvCDMj"}}},{"type":"message.part.updated","properties":{"part":{"id":"prt_b8e7d894b001iax8ZxtH2hvz0B","type":"tool","tool":"bash","messageID":"msg_b8e7d823f001HX1Rr9DYE7TYBf","state":{"status":"pending","input":{},"raw":""},"sessionID":"ses_471829192ffebHW9UmQGzvCDMj","callID":"call_WjZkpS6d8ZVtA7m8RrDBzA1J"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"id":"prt_b8e7d894b001iax8ZxtH2hvz0B","type":"tool","tool":"bash","messageID":"msg_b8e7d823f001HX1Rr9DYE7TYBf","state":{"status":"running","input":{"command":"git status","description":"Shows working tree status"},"time":{"start":1767622150547}},"sessionID":"ses_471829192ffebHW9UmQGzvCDMj","callID":"call_WjZkpS6d8ZVtA7m8RrDBzA1J"}}},{"type":"permission.asked","properties":{"patterns":["git status"],"id":"per_b8e7d89ad001fysFENZJxvDKzb","tool":{"messageID":"msg_b8e7d823f001HX1Rr9DYE7TYBf","callID":"call_WjZkpS6d8ZVtA7m8RrDBzA1J"},"permission":"bash","always":["git status*"],"sessionID":"ses_471829192ffebHW9UmQGzvCDMj","metadata":{}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"permission.replied","properties":{"requestID":"per_b8e7d89ad001fysFENZJxvDKzb","reply":"reject","sessionID":"ses_471829192ffebHW9UmQGzvCDMj"}},{"type":"message.part.updated","properties":{"part":{"id":"prt_b8e7d894b001iax8ZxtH2hvz0B","type":"tool","tool":"bash","messageID":"msg_b8e7d823f001HX1Rr9DYE7TYBf","state":{"status":"error","error":"Error: The user rejected permission to use this specific tool call.","input":{"command":"git status","description":"Shows working tree status"},"time":{"start":1767622150547,"end":1767622156196}},"sessionID":"ses_471829192ffebHW9UmQGzvCDMj","callID":"call_WjZkpS6d8ZVtA7m8RrDBzA1J"}}},{"type":"message.part.updated","properties":{"part":{"cost":0,"id":"prt_b8e7d9fa7001vEc0lpWy1MDUdb","type":"step-finish","snapshot":"f28b6ec26f4d2f0f1c8fdb665276f5628facc967","reason":"tool-calls","tokens":{"cache":{"read":0,"write":0},"output":23,"input":20614,"reasoning":0},"sessionID":"ses_471829192ffebHW9UmQGzvCDMj","messageID":"msg_b8e7d823f001HX1Rr9DYE7TYBf"}}},{"type":"message.updated","properties":{"info":{"parentID":"msg_b8e7d8222001ZAc4G1t5RfHzou","role":"assistant","finish":"tool-calls","time":{"created":1767622148672},"path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"sessionID":"ses_471829192ffebHW9UmQGzvCDMj","mode":"build","modelID":"gpt-4.1","providerID":"github-copilot","agent":"build","tokens":{"cache":{"read":0,"write":0},"output":23,"input":20614,"reasoning":0},"id":"msg_b8e7d823f001HX1Rr9DYE7TYBf","cost":0}}},{"type":"message.updated","properties":{"info":{"parentID":"msg_b8e7d8222001ZAc4G1t5RfHzou","role":"assistant","finish":"tool-calls","time":{"created":1767622148672,"completed":1767622156230},"path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"sessionID":"ses_471829192ffebHW9UmQGzvCDMj","mode":"build","modelID":"gpt-4.1","providerID":"github-copilot","agent":"build","tokens":{"cache":{"read":0,"write":0},"output":23,"input":20614,"reasoning":0},"id":"msg_b8e7d823f001HX1Rr9DYE7TYBf","cost":0}}},{"type":"session.idle","properties":{"sessionID":"ses_471829192ffebHW9UmQGzvCDMj"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"id":"msg_b8e7d8222001ZAc4G1t5RfHzou","role":"user","sessionID":"ses_471829192ffebHW9UmQGzvCDMj","time":{"created":1767622148643},"summary":{"diffs":[]},"model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","agent":"build"}}},{"type":"session.updated","properties":{"info":{"version":"1.1.2","time":{"created":1767622143597,"updated":1767622156244},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","summary":{"additions":0,"files":0,"deletions":0},"id":"ses_471829192ffebHW9UmQGzvCDMj","title":"New session - 2026-01-05T14:09:03.597Z","directory":"/home/francis/Projects/_nvim/opencode.nvim"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"id":"msg_b8e7d8222001ZAc4G1t5RfHzou","role":"user","sessionID":"ses_471829192ffebHW9UmQGzvCDMj","time":{"created":1767622148643},"summary":{"diffs":[],"title":"Requesting git status and listing changed files"},"model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","agent":"build"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"id":"msg_b8e7d8222001ZAc4G1t5RfHzou","role":"user","sessionID":"ses_471829192ffebHW9UmQGzvCDMj","time":{"created":1767622148643},"summary":{"diffs":[],"title":"Running git status to list changed files"},"model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","agent":"build"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"session.updated","properties":{"info":{"version":"1.1.2","time":{"created":1767622143597,"updated":1767622165039},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","summary":{"additions":0,"files":0,"deletions":0},"id":"ses_471829192ffebHW9UmQGzvCDMj","title":"Listing changed files with git status","directory":"/home/francis/Projects/_nvim/opencode.nvim"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]}]
+[
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "user",
+ "id": "msg_b8e7d8222001ZAc4G1t5RfHzou",
+ "agent": "build",
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "time": { "created": 1767622148643 }
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "id": "prt_b8e7d8223001xEcei9tomaINdJ",
+ "type": "text",
+ "messageID": "msg_b8e7d8222001ZAc4G1t5RfHzou",
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "text": "@no-trust run a git status and tell me what files are changed"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "id": "prt_b8e7d8223002NzjiAm7x7Zcg8b",
+ "type": "text",
+ "synthetic": true,
+ "messageID": "msg_b8e7d8222001ZAc4G1t5RfHzou",
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "text": "Called the Read tool with the following input: {\"filePath\":\"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\"}"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "id": "prt_b8e7d82270012OhYhykY53tJuV",
+ "type": "text",
+ "synthetic": true,
+ "messageID": "msg_b8e7d8222001ZAc4G1t5RfHzou",
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "text": "\n00001| local context_module = require('opencode.context')\n00002| local icons = require('opencode.ui.icons')\n00003| local util = require('opencode.util')\n00004| local Output = require('opencode.ui.output')\n00005| local state = require('opencode.state')\n00006| local config = require('opencode.config')\n00007| local snapshot = require('opencode.snapshot')\n00008| local mention = require('opencode.ui.mention')\n00009| \n00010| local M = {}\n00011| \n00012| M.separator = {\n00013| '----',\n00014| '',\n00015| }\n00016| \n00017| ---@param output Output\n00018| ---@param part OpencodeMessagePart\n00019| function M._format_reasoning(output, part)\n00020| local text = vim.trim(part.text or '')\n00021| if text == '' then\n00022| return\n00023| end\n00024| \n00025| local start_line = output:get_line_count() + 1\n00026| \n00027| local title = 'Reasoning'\n00028| local time = part.time\n00029| if time and type(time) == 'table' and time.start then\n00030| local start_text = util.format_time(time.start) or ''\n00031| local end_text = (time['end'] and util.format_time(time['end'])) or nil\n00032| if end_text and end_text ~= '' then\n00033| title = string.format('%s (%s - %s)', title, start_text, end_text)\n00034| elseif start_text ~= '' then\n00035| title = string.format('%s (%s)', title, start_text)\n00036| end\n00037| end\n00038| \n00039| M._format_action(output, icons.get('reasoning') .. ' ' .. title, '')\n00040| \n00041| if config.ui.output.tools.show_reasoning_output then\n00042| output:add_empty_line()\n00043| output:add_lines(vim.split(text, '\\n'))\n00044| output:add_empty_line()\n00045| end\n00046| \n00047| local end_line = output:get_line_count()\n00048| if end_line - start_line > 1 then\n00049| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1, 'OpencodeReasoningText')\n00050| else\n00051| output:add_extmark(start_line - 1, {\n00052| line_hl_group = 'OpencodeReasoningText',\n00053| } --[[@as OutputExtmark]])\n00054| end\n00055| end\n00056| \n00057| function M._handle_permission_request(output, part)\n00058| if part.state and part.state.status == 'error' and part.state.error then\n00059| if part.state.error:match('rejected permission') then\n00060| state.current_permission = nil\n00061| else\n00062| vim.notify('Unknown part state error: ' .. part.state.error)\n00063| end\n00064| return\n00065| end\n00066| \n00067| M._format_permission_request(output)\n00068| end\n00069| \n00070| function M._format_permission_request(output)\n00071| local keys\n00072| \n00073| if require('opencode.ui.ui').is_opencode_focused() then\n00074| keys = {\n00075| config.keymap.permission.accept,\n00076| config.keymap.permission.accept_all,\n00077| config.keymap.permission.deny,\n00078| }\n00079| else\n00080| keys = {\n00081| config.get_key_for_function('editor', 'permission_accept'),\n00082| config.get_key_for_function('editor', 'permission_accept_all'),\n00083| config.get_key_for_function('editor', 'permission_deny'),\n00084| }\n00085| end\n00086| \n00087| output:add_empty_line()\n00088| output:add_line('> [!WARNING] Permission required to run this tool.')\n00089| output:add_line('>')\n00090| output:add_line(('> Accept `%s` Always `%s` Deny `%s`'):format(unpack(keys)))\n00091| output:add_empty_line()\n00092| end\n00093| \n00094| ---Calculate statistics for reverted messages and tool calls\n00095| ---@param messages {info: MessageInfo, parts: OpencodeMessagePart[]}[] All messages in the session\n00096| ---@param revert_index number Index of the message where revert occurred\n00097| ---@param revert_info SessionRevertInfo Revert information\n00098| ---@return {messages: number, tool_calls: number, files: table}\n00099| function M._calculate_revert_stats(messages, revert_index, revert_info)\n00100| local stats = {\n00101| messages = 0,\n00102| tool_calls = 0,\n00103| files = {}, -- { [filename] = { additions = n, deletions = m } }\n00104| }\n00105| \n00106| for i = revert_index, #messages do\n00107| local msg = messages[i]\n00108| if msg.info.role == 'user' then\n00109| stats.messages = stats.messages + 1\n00110| end\n00111| if msg.parts then\n00112| for _, part in ipairs(msg.parts) do\n00113| if part.type == 'tool' then\n00114| stats.tool_calls = stats.tool_calls + 1\n00115| end\n00116| end\n00117| end\n00118| end\n00119| \n00120| if revert_info.diff then\n00121| local current_file = nil\n00122| for line in revert_info.diff:gmatch('[^\\r\\n]+') do\n00123| local file_a = line:match('^%-%-%- ([ab]/.+)')\n00124| local file_b = line:match('^%+%+%+ ([ab]/.+)')\n00125| if file_b then\n00126| current_file = file_b:gsub('^[ab]/', '')\n00127| if not stats.files[current_file] then\n00128| stats.files[current_file] = { additions = 0, deletions = 0 }\n00129| end\n00130| elseif file_a then\n00131| current_file = file_a:gsub('^[ab]/', '')\n00132| if not stats.files[current_file] then\n00133| stats.files[current_file] = { additions = 0, deletions = 0 }\n00134| end\n00135| elseif line:sub(1, 1) == '+' and not line:match('^%+%+%+') then\n00136| if current_file then\n00137| stats.files[current_file].additions = stats.files[current_file].additions + 1\n00138| end\n00139| elseif line:sub(1, 1) == '-' and not line:match('^%-%-%-') then\n00140| if current_file then\n00141| stats.files[current_file].deletions = stats.files[current_file].deletions + 1\n00142| end\n00143| end\n00144| end\n00145| end\n00146| \n00147| return stats\n00148| end\n00149| \n00150| ---Format the revert callout with statistics\n00151| ---@param session_data OpencodeMessage[] All messages in the session\n00152| ---@param start_idx number Index of the message where revert occurred\n00153| ---@return Output output object representing the lines, extmarks, and actions\n00154| function M._format_revert_message(session_data, start_idx)\n00155| local output = Output.new()\n00156| local stats = M._calculate_revert_stats(session_data, start_idx, state.active_session.revert)\n00157| local message_text = stats.messages == 1 and 'message' or 'messages'\n00158| local tool_text = stats.tool_calls == 1 and 'tool call' or 'tool calls'\n00159| \n00160| output:add_lines(M.separator)\n00161| output:add_line(\n00162| string.format('> %d %s reverted, %d %s reverted', stats.messages, message_text, stats.tool_calls, tool_text)\n00163| )\n00164| output:add_line('>')\n00165| output:add_line('> type `/redo` to restore.')\n00166| output:add_empty_line()\n00167| \n00168| if stats.files and next(stats.files) then\n00169| for file, fstats in pairs(stats.files) do\n00170| local file_diff = {}\n00171| if fstats.additions > 0 then\n00172| table.insert(file_diff, '+' .. fstats.additions)\n00173| end\n00174| if fstats.deletions > 0 then\n00175| table.insert(file_diff, '-' .. fstats.deletions)\n00176| end\n00177| if #file_diff > 0 then\n00178| local line_str = string.format(icons.get('file') .. '%s: %s', file, table.concat(file_diff, ' '))\n00179| local line_idx = output:add_line(line_str)\n00180| local col = #(' ' .. file .. ': ')\n00181| for _, diff in ipairs(file_diff) do\n00182| local hl_group = diff:sub(1, 1) == '+' and 'OpencodeDiffAddText' or 'OpencodeDiffDeleteText'\n00183| output:add_extmark(line_idx - 1, {\n00184| virt_text = { { diff, hl_group } },\n00185| virt_text_pos = 'inline',\n00186| virt_text_win_col = col,\n00187| priority = 1000,\n00188| } --[[@as OutputExtmark]])\n00189| col = col + #diff + 1\n00190| end\n00191| end\n00192| end\n00193| end\n00194| return output\n00195| end\n00196| \n00197| local function add_action(output, text, action_type, args, key, line)\n00198| -- actions use api-indexing (e.g. 0 indexed)\n00199| line = (line or output:get_line_count()) - 1\n00200| output:add_action({\n00201| text = text,\n00202| type = action_type,\n00203| args = args,\n00204| key = key,\n00205| display_line = line,\n00206| range = { from = line, to = line },\n00207| })\n00208| end\n00209| \n00210| ---@param output Output Output object to write to\n00211| ---@param part OpencodeMessagePart\n00212| function M._format_patch(output, part)\n00213| if not part.hash then\n00214| return\n00215| end\n00216| \n00217| local restore_points = snapshot.get_restore_points_by_parent(part.hash) or {}\n00218| M._format_action(output, icons.get('snapshot') .. ' Created Snapshot', vim.trim(part.hash:sub(1, 8)))\n00219| \n00220| -- Anchor all snapshot-level actions to the snapshot header line\n00221| add_action(output, '[R]evert file', 'diff_revert_selected_file', { part.hash }, 'R')\n00222| add_action(output, 'Revert [A]ll', 'diff_revert_all', { part.hash }, 'A')\n00223| add_action(output, '[D]iff', 'diff_open', { part.hash }, 'D')\n00224| \n00225| if #restore_points > 0 then\n00226| for _, restore_point in ipairs(restore_points) do\n00227| output:add_line(\n00228| string.format(\n00229| ' %s Restore point `%s` - %s ',\n00230| icons.get('restore_point'),\n00231| vim.trim(restore_point.id:sub(1, 8)),\n00232| util.format_time(restore_point.created_at)\n00233| )\n00234| )\n00235| add_action(output, 'Restore [A]ll', 'diff_restore_snapshot_all', { restore_point.id }, 'A')\n00236| add_action(output, '[R]estore file', 'diff_restore_snapshot_file', { restore_point.id }, 'R')\n00237| end\n00238| end\n00239| end\n00240| \n00241| ---@param output Output Output object to write to\n00242| ---@param message MessageInfo\n00243| function M._format_error(output, message)\n00244| output:add_empty_line()\n00245| M._format_callout(output, 'ERROR', vim.inspect(message.error))\n00246| end\n00247| \n00248| ---@param message OpencodeMessage\n00249| ---@return Output\n00250| function M.format_message_header(message)\n00251| local output = Output.new()\n00252| \n00253| output:add_lines(M.separator)\n00254| local role = message.info.role or 'unknown'\n00255| local icon = message.info.role == 'user' and icons.get('header_user') or icons.get('header_assistant')\n00256| \n00257| local time = message.info.time and message.info.time.created or nil\n00258| local time_text = (time and ' (' .. util.format_time(time) .. ')' or '')\n00259| local role_hl = 'OpencodeMessageRole' .. role:sub(1, 1):upper() .. role:sub(2)\n00260| local model_text = message.info.modelID and ' ' .. message.info.modelID or ''\n00261| \n00262| local debug_text = config.debug.show_ids and ' [' .. message.info.id .. ']' or ''\n00263| \n00264| local display_name\n00265| if role == 'assistant' then\n00266| local mode = message.info.mode\n00267| if mode and mode ~= '' then\n00268| display_name = mode:upper()\n00269| else\n00270| -- For the most recent assistant message, show current_mode if mode is missing\n00271| -- This handles new messages that haven't been stamped yet\n00272| local is_last_message = #state.messages == 0 or message.info.id == state.messages[#state.messages].info.id\n00273| if is_last_message and state.current_mode and state.current_mode ~= '' then\n00274| display_name = state.current_mode:upper()\n00275| else\n00276| display_name = 'ASSISTANT'\n00277| end\n00278| end\n00279| else\n00280| display_name = role:upper()\n00281| end\n00282| \n00283| output:add_extmark(output:get_line_count() - 1, {\n00284| virt_text = {\n00285| { icon, role_hl },\n00286| { ' ' },\n00287| { display_name, role_hl },\n00288| { model_text, 'OpencodeHint' },\n00289| { time_text, 'OpencodeHint' },\n00290| { debug_text, 'OpencodeHint' },\n00291| },\n00292| virt_text_win_col = -3,\n00293| priority = 10,\n00294| } --[[@as OutputExtmark]])\n00295| \n00296| -- Only want to show the error if we have no parts. If we have parts, they'll\n00297| -- handle rendering the error\n00298| if\n00299| role == 'assistant'\n00300| and message.info.error\n00301| and message.info.error ~= ''\n00302| and (not message.parts or #message.parts == 0)\n00303| then\n00304| local error = message.info.error\n00305| local error_message = error.data and error.data.message or vim.inspect(error)\n00306| \n00307| output:add_line('')\n00308| M._format_callout(output, 'ERROR', error_message)\n00309| end\n00310| \n00311| output:add_line('')\n00312| return output\n00313| end\n00314| \n00315| ---@param output Output Output object to write to\n00316| ---@param callout string Callout type (e.g., 'ERROR', 'TODO')\n00317| ---@param text string Callout text content\n00318| ---@param title? string Optional title for the callout\n00319| function M._format_callout(output, callout, text, title)\n00320| title = title and title .. ' ' or ''\n00321| local win_width = (state.windows and state.windows.output_win and vim.api.nvim_win_is_valid(state.windows.output_win))\n00322| and vim.api.nvim_win_get_width(state.windows.output_win)\n00323| or config.ui.window_width\n00324| or 80\n00325| if #text > win_width - 4 then\n00326| local ok, substituted = pcall(vim.fn.substitute, text, '\\v(.{' .. (win_width - 8) .. '})', '\\1\\n', 'g')\n00327| text = ok and substituted or text\n00328| end\n00329| \n00330| -- Trim off any trailing newlines so there isn't an extra line in the\n00331| -- extmarks section\n00332| local lines = vim.split(text:gsub('\\n$', ''), '\\n')\n00333| if #lines == 1 and title == '' then\n00334| output:add_line('> [!' .. callout .. '] ' .. lines[1])\n00335| else\n00336| output:add_line('> [!' .. callout .. ']' .. title)\n00337| output:add_line('>')\n00338| output:add_lines(lines, '> ')\n00339| end\n00340| end\n00341| \n00342| ---@param output Output Output object to write to\n00343| ---@param text string\n00344| ---@param message? OpencodeMessage Optional message object to extract mentions from\n00345| function M._format_user_prompt(output, text, message)\n00346| local start_line = output:get_line_count()\n00347| \n00348| output:add_lines(vim.split(text, '\\n'))\n00349| \n00350| local end_line = output:get_line_count()\n00351| \n00352| local end_line_extmark_offset = 0\n00353| \n00354| local mentions = {}\n00355| if message and message.parts then\n00356| -- message.parts will only be filled out on a re-render\n00357| -- we need to collect the mentions here\n00358| for _, part in ipairs(message.parts) do\n00359| if part.type == 'file' then\n00360| -- we're rerendering this part and we have files, the space after the user prompt\n00361| -- also needs an extmark\n00362| end_line_extmark_offset = 1\n00363| if part.source and part.source.text then\n00364| table.insert(mentions, part.source.text)\n00365| end\n00366| elseif part.type == 'agent' then\n00367| if part.source then\n00368| table.insert(mentions, part.source)\n00369| end\n00370| end\n00371| end\n00372| end\n00373| \n00374| if #mentions > 0 then\n00375| mention.highlight_mentions_in_output(output, text, mentions, start_line)\n00376| end\n00377| \n00378| M._add_vertical_border(output, start_line, end_line + end_line_extmark_offset, 'OpencodeMessageRoleUser', -3)\n00379| end\n00380| \n00381| ---@param output Output Output object to write to\n00382| ---@param part OpencodeMessagePart\n00383| function M._format_selection_context(output, part)\n00384| local json = context_module.decode_json_context(part.text or '', 'selection')\n00385| if not json then\n00386| return\n00387| end\n00388| local start_line = output:get_line_count()\n00389| output:add_lines(vim.split(json.content or '', '\\n'))\n00390| output:add_empty_line()\n00391| \n00392| local end_line = output:get_line_count()\n00393| \n00394| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00395| end\n00396| \n00397| ---@param output Output Output object to write to\n00398| ---@param part OpencodeMessagePart\n00399| function M._format_cursor_data_context(output, part)\n00400| local json = context_module.decode_json_context(part.text or '', 'cursor-data')\n00401| if not json then\n00402| return\n00403| end\n00404| local start_line = output:get_line_count()\n00405| output:add_line('Line ' .. json.line .. ':')\n00406| output:add_lines(vim.split(json.line_content or '', '\\n'))\n00407| output:add_empty_line()\n00408| \n00409| local end_line = output:get_line_count()\n00410| \n00411| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00412| end\n00413| \n00414| ---@param output Output Output object to write to\n00415| ---@param part OpencodeMessagePart\n00416| function M._format_diagnostics_context(output, part)\n00417| local json = context_module.decode_json_context(part.text or '', 'diagnostics')\n00418| if not json then\n00419| return\n00420| end\n00421| local start_line = output:get_line_count()\n00422| local diagnostics = json.content --[[@as OpencodeDiagnostic[] ]]\n00423| if not diagnostics or type(diagnostics) ~= 'table' or #diagnostics == 0 then\n00424| return\n00425| end\n00426| \n00427| local diagnostics_count = { error = 0, warn = 0, info = 0 }\n00428| local diagnostics_icons = {\n00429| error = icons.get('error'),\n00430| warn = icons.get('warning'),\n00431| info = icons.get('info'),\n00432| }\n00433| \n00434| for _, diag in ipairs(diagnostics) do\n00435| local name = vim.diagnostic.severity[diag.severity]:lower()\n00436| diagnostics_count[name] = diagnostics_count[name] + 1\n00437| end\n00438| \n00439| local diag_line = '**Diagnostics:**'\n00440| for name, count in pairs(diagnostics_count) do\n00441| if count > 0 then\n00442| diag_line = diag_line .. (string.format(' %s(%d)', diagnostics_icons[name], count))\n00443| end\n00444| end\n00445| output:add_line(diag_line)\n00446| output:add_empty_line()\n00447| local end_line = output:get_line_count()\n00448| \n00449| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00450| end\n00451| \n00452| ---Format and display the file path in the context\n00453| ---@param output Output Output object to write to\n00454| ---@param path string|nil File path\n00455| function M._format_context_file(output, path)\n00456| if not path or path == '' then\n00457| return\n00458| end\n00459| local cwd = vim.fn.getcwd()\n00460| if vim.startswith(path, cwd) then\n00461| path = path:sub(#cwd + 2)\n00462| end\n00463| return output:add_line(string.format('[%s](%s)', path, path))\n00464| end\n00465| \n00466| ---@param output Output Output object to write to\n00467| ---@param text string\n00468| function M._format_assistant_message(output, text)\n00469| local reference_picker = require('opencode.ui.reference_picker')\n00470| local references = reference_picker.parse_references(text, '')\n00471| \n00472| -- If no references, just add the text as-is\n00473| if #references == 0 then\n00474| output:add_lines(vim.split(text, '\\n'))\n00475| return\n00476| end\n00477| \n00478| -- Sort references by match_start position (ascending)\n00479| table.sort(references, function(a, b)\n00480| return a.match_start < b.match_start\n00481| end)\n00482| \n00483| -- Build a new text with icons inserted before each reference\n00484| local result = ''\n00485| local last_pos = 1\n00486| local ref_icon = icons.get('reference')\n00487| \n00488| for _, ref in ipairs(references) do\n00489| -- Add text before this reference\n00490| result = result .. text:sub(last_pos, ref.match_start - 1)\n00491| -- Add the icon and the reference\n00492| result = result .. ref_icon .. text:sub(ref.match_start, ref.match_end)\n00493| last_pos = ref.match_end + 1\n00494| end\n00495| \n00496| -- Add any remaining text after the last reference\n00497| if last_pos <= #text then\n00498| result = result .. text:sub(last_pos)\n00499| end\n00500| \n00501| output:add_lines(vim.split(result, '\\n'))\n00502| end\n00503| \n00504| ---@param output Output Output object to write to\n00505| ---@param tool_type string Tool type (e.g., 'run', 'read', 'edit', etc.)\n00506| ---@param value string Value associated with the action (e.g., filename, command)\n00507| function M._format_action(output, tool_type, value)\n00508| if not tool_type or not value then\n00509| return\n00510| end\n00511| local line = string.format('**%s** %s', tool_type, value and #value > 0 and ('`' .. value .. '`') or '')\n00512| \n00513| output:add_line(line)\n00514| end\n00515| \n00516| ---@param output Output Output object to write to\n00517| ---@param input BashToolInput data for the tool\n00518| ---@param metadata BashToolMetadata Metadata for the tool use\n00519| function M._format_bash_tool(output, input, metadata)\n00520| M._format_action(output, icons.get('run') .. ' run', input and input.description)\n00521| \n00522| if not config.ui.output.tools.show_output then\n00523| return\n00524| end\n00525| \n00526| if metadata.output or metadata.command or input.command then\n00527| local command = input.command or metadata.command or ''\n00528| local command_output = metadata.output and metadata.output ~= '' and ('\\n' .. metadata.output) or ''\n00529| M._format_code(output, vim.split('> ' .. command .. '\\n' .. command_output, '\\n'), 'bash')\n00530| end\n00531| end\n00532| \n00533| ---@param output Output Output object to write to\n00534| ---@param tool_type string Tool type (e.g., 'read', 'edit', 'write')\n00535| ---@param input FileToolInput data for the tool\n00536| ---@param metadata FileToolMetadata Metadata for the tool use\n00537| function M._format_file_tool(output, tool_type, input, metadata)\n00538| local file_name = input and vim.fn.fnamemodify(input.filePath, ':t') or ''\n00539| local file_type = input and util.get_markdown_filetype(input.filePath) or ''\n00540| local tool_action_icons = { read = icons.get('read'), edit = icons.get('edit'), write = icons.get('write') }\n00541| \n00542| M._format_action(output, tool_action_icons[tool_type] .. ' ' .. tool_type, file_name)\n00543| \n00544| if not config.ui.output.tools.show_output then\n00545| return\n00546| end\n00547| \n00548| if tool_type == 'edit' and metadata.diff then\n00549| M._format_diff(output, metadata.diff, file_type)\n00550| elseif tool_type == 'write' and input and input.content then\n00551| M._format_code(output, vim.split(input.content, '\\n'), file_type)\n00552| end\n00553| end\n00554| \n00555| ---@param output Output Output object to write to\n00556| ---@param title string\n00557| ---@param input TodoToolInput\n00558| function M._format_todo_tool(output, title, input)\n00559| M._format_action(output, icons.get('plan') .. ' plan', (title or ''))\n00560| if not config.ui.output.tools.show_output then\n00561| return\n00562| end\n00563| \n00564| local todos = input and input.todos or {}\n00565| \n00566| for _, item in ipairs(todos) do\n00567| local statuses = { in_progress = '-', completed = 'x', pending = ' ' }\n00568| output:add_line(string.format('- [%s] %s ', statuses[item.status], item.content))\n00569| end\n00570| end\n00571| \n00572| ---@param output Output Output object to write to\n00573| ---@param input GlobToolInput data for the tool\n00574| ---@param metadata GlobToolMetadata Metadata for the tool use\n00575| function M._format_glob_tool(output, input, metadata)\n00576| M._format_action(output, icons.get('search') .. ' glob', input and input.pattern)\n00577| if not config.ui.output.tools.show_output then\n00578| return\n00579| end\n00580| local prefix = metadata.truncated and ' more than' or ''\n00581| output:add_line(string.format('Found%s `%d` file(s):', prefix, metadata.count or 0))\n00582| end\n00583| \n00584| ---@param output Output Output object to write to\n00585| ---@param input GrepToolInput data for the tool\n00586| ---@param metadata GrepToolMetadata Metadata for the tool use\n00587| function M._format_grep_tool(output, input, metadata)\n00588| input = input or { path = '', include = '', pattern = '' }\n00589| \n00590| local grep_str = string.format('%s` `%s', (input.path or input.include) or '', input.pattern or '')\n00591| \n00592| M._format_action(output, icons.get('search') .. ' grep', grep_str)\n00593| if not config.ui.output.tools.show_output then\n00594| return\n00595| end\n00596| local prefix = metadata.truncated and ' more than' or ''\n00597| output:add_line(\n00598| string.format('Found%s `%d` match' .. (metadata.matches ~= 1 and 'es' or ''), prefix, metadata.matches or 0)\n00599| )\n00600| end\n00601| \n00602| ---@param output Output Output object to write to\n00603| ---@param input WebFetchToolInput data for the tool\n00604| function M._format_webfetch_tool(output, input)\n00605| M._format_action(output, icons.get('web') .. ' fetch', input and input.url)\n00606| end\n00607| \n00608| ---@param output Output Output object to write to\n00609| ---@param input ListToolInput\n00610| ---@param metadata ListToolMetadata\n00611| ---@param tool_output string\n00612| function M._format_list_tool(output, input, metadata, tool_output)\n00613| M._format_action(output, icons.get('list') .. ' list', input and input.path or '')\n00614| if not config.ui.output.tools.show_output then\n00615| return\n00616| end\n00617| local lines = vim.split(vim.trim(tool_output or ''), '\\n')\n00618| if #lines < 1 or metadata.count == 0 then\n00619| output:add_line('No files found.')\n00620| return\n00621| end\n00622| if #lines > 1 then\n00623| output:add_line('Files:')\n00624| for i = 2, #lines do\n00625| local file = vim.trim(lines[i])\n00626| if file ~= '' then\n00627| output:add_line(' • ' .. file)\n00628| end\n00629| end\n00630| end\n00631| if metadata.truncated then\n00632| output:add_line(string.format('Results truncated, showing first %d files', metadata.count or '?'))\n00633| end\n00634| end\n00635| \n00636| ---@param output Output Output object to write to\n00637| ---@param part OpencodeMessagePart\n00638| function M._format_tool(output, part)\n00639| local tool = part.tool\n00640| if not tool or not part.state then\n00641| return\n00642| end\n00643| \n00644| local start_line = output:get_line_count() + 1\n00645| local input = part.state.input or {}\n00646| local metadata = part.state.metadata or {}\n00647| local tool_output = part.state.output or ''\n00648| \n00649| if state.current_permission and state.current_permission.messageID == part.messageID then\n00650| metadata = state.current_permission.metadata or metadata\n00651| end\n00652| \n00653| if tool == 'bash' then\n00654| M._format_bash_tool(output, input --[[@as BashToolInput]], metadata --[[@as BashToolMetadata]])\n00655| elseif tool == 'read' or tool == 'edit' or tool == 'write' then\n00656| M._format_file_tool(output, tool, input --[[@as FileToolInput]], metadata --[[@as FileToolMetadata]])\n00657| elseif tool == 'todowrite' then\n00658| M._format_todo_tool(output, part.state.title, input --[[@as TodoToolInput]])\n00659| elseif tool == 'glob' then\n00660| M._format_glob_tool(output, input --[[@as GlobToolInput]], metadata --[[@as GlobToolMetadata]])\n00661| elseif tool == 'list' then\n00662| M._format_list_tool(output, input --[[@as ListToolInput]], metadata --[[@as ListToolMetadata]], tool_output)\n00663| elseif tool == 'grep' then\n00664| M._format_grep_tool(output, input --[[@as GrepToolInput]], metadata --[[@as GrepToolMetadata]])\n00665| elseif tool == 'webfetch' then\n00666| M._format_webfetch_tool(output, input --[[@as WebFetchToolInput]])\n00667| elseif tool == 'task' then\n00668| M._format_task_tool(output, input --[[@as TaskToolInput]], metadata --[[@as TaskToolMetadata]], tool_output)\n00669| else\n00670| M._format_action(output, icons.get('tool') .. ' tool', tool)\n00671| end\n00672| \n00673| if part.state.status == 'error' and part.state.error then\n00674| output:add_line('')\n00675| M._format_callout(output, 'ERROR', part.state.error)\n00676| ---@diagnostic disable-next-line: undefined-field\n00677| elseif part.state.input and part.state.input.error then\n00678| output:add_line('')\n00679| ---I'm not sure about the type with state.input.error\n00680| ---@diagnostic disable-next-line: undefined-field\n00681| M._format_callout(output, 'ERROR', part.state.input.error)\n00682| end\n00683| \n00684| if\n00685| state.current_permission\n00686| and (\n00687| (\n00688| state.current_permission.tool\n00689| and state.current_permission.tool.callID == part.callID\n00690| and state.current_permission.tool.messageID == part.messageID\n00691| )\n00692| ---@TODO this is for backward compatibility, remove later\n00693| or (state.current_permission.messageID == part.messageID and state.current_permission.callID == part.callID)\n00694| )\n00695| then\n00696| M._handle_permission_request(output, part)\n00697| end\n00698| \n00699| local end_line = output:get_line_count()\n00700| if end_line - start_line > 1 then\n00701| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1)\n00702| end\n00703| end\n00704| \n00705| ---@param output Output Output object to write to\n00706| ---@param input TaskToolInput data for the tool\n00707| ---@param metadata TaskToolMetadata Metadata for the tool use\n00708| ---@param tool_output string\n00709| function M._format_task_tool(output, input, metadata, tool_output)\n00710| local start_line = output:get_line_count() + 1\n00711| M._format_action(output, icons.get('task') .. ' task', input and input.description)\n00712| \n00713| if config.ui.output.tools.show_output then\n00714| if tool_output and tool_output ~= '' then\n00715| output:add_empty_line()\n00716| output:add_lines(vim.split(tool_output, '\\n'))\n00717| output:add_empty_line()\n00718| end\n00719| \n00720| if metadata.summary and type(metadata.summary) == 'table' then\n00721| for _, sub_part in ipairs(metadata.summary) do\n00722| if sub_part.type == 'tool' and sub_part.tool then\n00723| M._format_tool(output, sub_part)\n00724| end\n00725| end\n00726| end\n00727| end\n00728| \n00729| local end_line = output:get_line_count()\n00730| output:add_action({\n00731| text = '[S]elect Child Session',\n00732| type = 'select_child_session',\n00733| args = {},\n00734| key = 'S',\n00735| display_line = start_line - 1,\n00736| range = { from = start_line, to = end_line },\n00737| })\n00738| end\n00739| \n00740| ---@param output Output Output object to write to\n00741| ---@param lines string[]\n00742| ---@param language string\n00743| function M._format_code(output, lines, language)\n00744| output:add_empty_line()\n00745| --- NOTE: use longer code fence because lines could contain ```\n00746| output:add_line('`````' .. (language or ''))\n00747| output:add_lines(util.sanitize_lines(lines))\n00748| output:add_line('`````')\n00749| end\n00750| \n00751| ---@param output Output Output object to write to\n00752| ---@param code string\n00753| ---@param file_type string\n00754| function M._format_diff(output, code, file_type)\n00755| output:add_empty_line()\n00756| \n00757| --- NOTE: use longer code fence because code could contain ```\n00758| output:add_line('`````' .. file_type)\n00759| local lines = vim.split(code, '\\n')\n00760| if #lines > 5 then\n00761| lines = vim.list_slice(lines, 6)\n00762| end\n00763| \n00764| for _, line in ipairs(lines) do\n00765| local first_char = line:sub(1, 1)\n00766| if first_char == '+' or first_char == '-' then\n00767| local hl_group = first_char == '+' and 'OpencodeDiffAdd' or 'OpencodeDiffDelete'\n00768| output:add_line(' ' .. line:sub(2))\n00769| local line_idx = output:get_line_count()\n00770| output:add_extmark(line_idx - 1, function()\n00771| return {\n00772| end_col = 0,\n00773| end_row = line_idx,\n00774| virt_text = { { first_char, hl_group } },\n00775| hl_group = hl_group,\n00776| hl_eol = true,\n00777| priority = 5000,\n00778| right_gravity = true,\n00779| end_right_gravity = false,\n00780| virt_text_hide = false,\n00781| virt_text_pos = 'overlay',\n00782| virt_text_repeat_linebreak = false,\n00783| }\n00784| end)\n00785| else\n00786| output:add_line(line)\n00787| end\n00788| end\n00789| output:add_line('`````')\n00790| end\n00791| \n00792| ---@param output Output Output object to write to\n00793| ---@param start_line number\n00794| ---@param end_line number\n00795| ---@param hl_group string Highlight group for the border character\n00796| ---@param win_col number\n00797| ---@param text_hl_group? string Optional highlight group for the background/foreground of text lines\n00798| function M._add_vertical_border(output, start_line, end_line, hl_group, win_col, text_hl_group)\n00799| for line = start_line, end_line do\n00800| local extmark_opts = {\n00801| virt_text = { { require('opencode.ui.icons').get('border'), hl_group } },\n00802| virt_text_pos = 'overlay',\n00803| virt_text_win_col = win_col,\n00804| virt_text_repeat_linebreak = true,\n00805| }\n00806| \n00807| -- Add line highlight if text_hl_group is provided\n00808| if text_hl_group then\n00809| extmark_opts.line_hl_group = text_hl_group\n00810| end\n00811| \n00812| output:add_extmark(line - 1, extmark_opts --[[@as OutputExtmark]])\n00813| end\n00814| end\n00815| \n00816| ---Formats a single message part and returns the resulting output object\n00817| ---@param part OpencodeMessagePart The part to format\n00818| ---@param message? OpencodeMessage Optional message object to extract role and mentions from\n00819| ---@param is_last_part? boolean Whether this is the last part in the message, used to show an error if there is one\n00820| ---@return Output\n00821| function M.format_part(part, message, is_last_part)\n00822| local output = Output.new()\n00823| \n00824| if not message or not message.info or not message.info.role then\n00825| return output\n00826| end\n00827| \n00828| local content_added = false\n00829| local role = message.info.role\n00830| \n00831| if role == 'user' then\n00832| if part.type == 'text' and part.text then\n00833| if part.synthetic == true then\n00834| M._format_selection_context(output, part)\n00835| M._format_cursor_data_context(output, part)\n00836| M._format_diagnostics_context(output, part)\n00837| else\n00838| M._format_user_prompt(output, vim.trim(part.text), message)\n00839| content_added = true\n00840| end\n00841| elseif part.type == 'file' then\n00842| local file_line = M._format_context_file(output, part.filename)\n00843| if file_line then\n00844| M._add_vertical_border(output, file_line - 1, file_line, 'OpencodeMessageRoleUser', -3)\n00845| content_added = true\n00846| end\n00847| end\n00848| elseif role == 'assistant' then\n00849| if part.type == 'text' and part.text then\n00850| M._format_assistant_message(output, vim.trim(part.text))\n00851| content_added = true\n00852| elseif part.type == 'reasoning' and part.text then\n00853| M._format_reasoning(output, part)\n00854| content_added = true\n00855| elseif part.type == 'tool' then\n00856| M._format_tool(output, part)\n00857| content_added = true\n00858| elseif part.type == 'patch' and part.hash then\n00859| M._format_patch(output, part)\n00860| content_added = true\n00861| end\n00862| end\n00863| \n00864| if content_added then\n00865| output:add_empty_line()\n00866| end\n00867| \n00868| if is_last_part and role == 'assistant' and message.info.error and message.info.error ~= '' then\n00869| local error = message.info.error\n00870| local error_message = error.data and error.data.message or vim.inspect(error)\n00871| M._format_callout(output, 'ERROR', error_message)\n00872| output:add_empty_line()\n00873| end\n00874| \n00875| return output\n00876| end\n00877| \n00878| return M\n00879| \n\n(End of file - total 879 lines)\n"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "id": "prt_b8e7d8227002hZiHYfLznqKXjU",
+ "type": "file",
+ "url": "file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua",
+ "mime": "text/plain",
+ "messageID": "msg_b8e7d8222001ZAc4G1t5RfHzou",
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "filename": "lua/opencode/ui/formatter.lua"
+ }
+ }
+ },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "title": "New session - 2026-01-05T14:09:03.597Z",
+ "time": { "created": 1767622143597, "updated": 1767622148667 },
+ "version": "1.1.2",
+ "id": "ses_471829192ffebHW9UmQGzvCDMj",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim"
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "parentID": "msg_b8e7d8222001ZAc4G1t5RfHzou",
+ "role": "assistant",
+ "time": { "created": 1767622148672 },
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "mode": "build",
+ "modelID": "gpt-4.1",
+ "providerID": "github-copilot",
+ "agent": "build",
+ "tokens": { "cache": { "read": 0, "write": 0 }, "output": 0, "input": 0, "reasoning": 0 },
+ "id": "msg_b8e7d823f001HX1Rr9DYE7TYBf",
+ "cost": 0
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "id": "msg_b8e7d8222001ZAc4G1t5RfHzou",
+ "role": "user",
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "time": { "created": 1767622148643 },
+ "summary": { "diffs": [] },
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "agent": "build"
+ }
+ }
+ },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "version": "1.1.2",
+ "time": { "created": 1767622143597, "updated": 1767622148771 },
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "summary": { "additions": 0, "files": 0, "deletions": 0 },
+ "id": "ses_471829192ffebHW9UmQGzvCDMj",
+ "title": "New session - 2026-01-05T14:09:03.597Z",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "id": "prt_b8e7d8948001TJr45cBt0IJmwi",
+ "type": "step-start",
+ "snapshot": "f28b6ec26f4d2f0f1c8fdb665276f5628facc967",
+ "messageID": "msg_b8e7d823f001HX1Rr9DYE7TYBf",
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "id": "prt_b8e7d894b001iax8ZxtH2hvz0B",
+ "type": "tool",
+ "tool": "bash",
+ "messageID": "msg_b8e7d823f001HX1Rr9DYE7TYBf",
+ "state": { "status": "pending", "input": {}, "raw": "" },
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "callID": "call_WjZkpS6d8ZVtA7m8RrDBzA1J"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "id": "prt_b8e7d894b001iax8ZxtH2hvz0B",
+ "type": "tool",
+ "tool": "bash",
+ "messageID": "msg_b8e7d823f001HX1Rr9DYE7TYBf",
+ "state": {
+ "status": "running",
+ "input": { "command": "git status", "description": "Shows working tree status" },
+ "time": { "start": 1767622150547 }
+ },
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "callID": "call_WjZkpS6d8ZVtA7m8RrDBzA1J"
+ }
+ }
+ },
+ {
+ "type": "permission.asked",
+ "properties": {
+ "patterns": ["git status"],
+ "id": "per_b8e7d89ad001fysFENZJxvDKzb",
+ "tool": { "messageID": "msg_b8e7d823f001HX1Rr9DYE7TYBf", "callID": "call_WjZkpS6d8ZVtA7m8RrDBzA1J" },
+ "permission": "bash",
+ "always": ["git status*"],
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "metadata": {}
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "permission.replied",
+ "properties": {
+ "requestID": "per_b8e7d89ad001fysFENZJxvDKzb",
+ "reply": "reject",
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj"
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "id": "prt_b8e7d894b001iax8ZxtH2hvz0B",
+ "type": "tool",
+ "tool": "bash",
+ "messageID": "msg_b8e7d823f001HX1Rr9DYE7TYBf",
+ "state": {
+ "status": "error",
+ "error": "Error: The user rejected permission to use this specific tool call.",
+ "input": { "command": "git status", "description": "Shows working tree status" },
+ "time": { "start": 1767622150547, "end": 1767622156196 }
+ },
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "callID": "call_WjZkpS6d8ZVtA7m8RrDBzA1J"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "cost": 0,
+ "id": "prt_b8e7d9fa7001vEc0lpWy1MDUdb",
+ "type": "step-finish",
+ "snapshot": "f28b6ec26f4d2f0f1c8fdb665276f5628facc967",
+ "reason": "tool-calls",
+ "tokens": { "cache": { "read": 0, "write": 0 }, "output": 23, "input": 20614, "reasoning": 0 },
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "messageID": "msg_b8e7d823f001HX1Rr9DYE7TYBf"
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "parentID": "msg_b8e7d8222001ZAc4G1t5RfHzou",
+ "role": "assistant",
+ "finish": "tool-calls",
+ "time": { "created": 1767622148672 },
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "mode": "build",
+ "modelID": "gpt-4.1",
+ "providerID": "github-copilot",
+ "agent": "build",
+ "tokens": { "cache": { "read": 0, "write": 0 }, "output": 23, "input": 20614, "reasoning": 0 },
+ "id": "msg_b8e7d823f001HX1Rr9DYE7TYBf",
+ "cost": 0
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "parentID": "msg_b8e7d8222001ZAc4G1t5RfHzou",
+ "role": "assistant",
+ "finish": "tool-calls",
+ "time": { "created": 1767622148672, "completed": 1767622156230 },
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "mode": "build",
+ "modelID": "gpt-4.1",
+ "providerID": "github-copilot",
+ "agent": "build",
+ "tokens": { "cache": { "read": 0, "write": 0 }, "output": 23, "input": 20614, "reasoning": 0 },
+ "id": "msg_b8e7d823f001HX1Rr9DYE7TYBf",
+ "cost": 0
+ }
+ }
+ },
+ { "type": "session.idle", "properties": { "sessionID": "ses_471829192ffebHW9UmQGzvCDMj" } },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "id": "msg_b8e7d8222001ZAc4G1t5RfHzou",
+ "role": "user",
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "time": { "created": 1767622148643 },
+ "summary": { "diffs": [] },
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "agent": "build"
+ }
+ }
+ },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "version": "1.1.2",
+ "time": { "created": 1767622143597, "updated": 1767622156244 },
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "summary": { "additions": 0, "files": 0, "deletions": 0 },
+ "id": "ses_471829192ffebHW9UmQGzvCDMj",
+ "title": "New session - 2026-01-05T14:09:03.597Z",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "id": "msg_b8e7d8222001ZAc4G1t5RfHzou",
+ "role": "user",
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "time": { "created": 1767622148643 },
+ "summary": { "diffs": [], "title": "Requesting git status and listing changed files" },
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "agent": "build"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "id": "msg_b8e7d8222001ZAc4G1t5RfHzou",
+ "role": "user",
+ "sessionID": "ses_471829192ffebHW9UmQGzvCDMj",
+ "time": { "created": 1767622148643 },
+ "summary": { "diffs": [], "title": "Running git status to list changed files" },
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "agent": "build"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "version": "1.1.2",
+ "time": { "created": 1767622143597, "updated": 1767622165039 },
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "summary": { "additions": 0, "files": 0, "deletions": 0 },
+ "id": "ses_471829192ffebHW9UmQGzvCDMj",
+ "title": "Listing changed files with git status",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] }
+]
diff --git a/tests/data/permission-ask-new.expected.json b/tests/data/permission-ask-new.expected.json
index 1c9edfe9..1c2520a8 100644
--- a/tests/data/permission-ask-new.expected.json
+++ b/tests/data/permission-ask-new.expected.json
@@ -1 +1,639 @@
-{"extmarks":[[1,1,0,{"virt_text_repeat_linebreak":false,"right_gravity":true,"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2026-01-05 14:07:54)","OpencodeHint"],[" [msg_b8e7c60a2001Kisjwk2mVB4dye]","OpencodeHint"]],"ns_id":3,"virt_text_win_col":-3,"priority":10,"virt_text_hide":false,"virt_text_pos":"win_col"}],[2,2,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_win_col":-3,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[3,3,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_win_col":-3,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[4,4,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_win_col":-3,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[5,5,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_win_col":-3,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[6,6,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_win_col":-3,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[7,7,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_win_col":-3,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[8,8,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_win_col":-3,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[9,10,0,{"virt_text_repeat_linebreak":false,"right_gravity":true,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2026-01-05 14:07:54)","OpencodeHint"],[" [msg_b8e7c60f1001aEWYlAaDRXQ4aJ]","OpencodeHint"]],"ns_id":3,"virt_text_win_col":-3,"priority":10,"virt_text_hide":false,"virt_text_pos":"win_col"}],[10,12,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_win_col":-1,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[11,13,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_win_col":-1,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[12,14,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_win_col":-1,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[13,15,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_win_col":-1,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[14,16,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_win_col":-1,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[15,17,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_win_col":-1,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[16,20,0,{"virt_text_repeat_linebreak":false,"right_gravity":true,"virt_text":[[" ","OpencodeMessageRoleSystem"],[" "],["SYSTEM","OpencodeMessageRoleSystem"],["","OpencodeHint"],["","OpencodeHint"],[" [permission-display-message]","OpencodeHint"]],"ns_id":3,"virt_text_win_col":-3,"priority":10,"virt_text_hide":false,"virt_text_pos":"win_col"}],[17,22,0,{"line_hl_group":"OpencodePermissionTitle","right_gravity":true,"priority":4096,"ns_id":3}],[18,22,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodePermissionBorder"]],"ns_id":3,"virt_text_win_col":-2,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[19,23,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodePermissionBorder"]],"ns_id":3,"virt_text_win_col":-2,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[20,24,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodePermissionBorder"]],"ns_id":3,"virt_text_win_col":-2,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[21,25,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodePermissionBorder"]],"ns_id":3,"virt_text_win_col":-2,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[22,26,0,{"line_hl_group":"OpencodeDialogOptionHover","right_gravity":true,"priority":4096,"ns_id":3}],[23,26,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodePermissionBorder"]],"ns_id":3,"virt_text_win_col":-2,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[24,26,2,{"virt_text_repeat_linebreak":false,"right_gravity":true,"virt_text":[["› ","OpencodeDialogOptionHover"]],"ns_id":3,"priority":4096,"virt_text_hide":false,"virt_text_pos":"overlay"}],[25,27,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodePermissionBorder"]],"ns_id":3,"virt_text_win_col":-2,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[26,28,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodePermissionBorder"]],"ns_id":3,"virt_text_win_col":-2,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[27,29,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodePermissionBorder"]],"ns_id":3,"virt_text_win_col":-2,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}],[28,30,0,{"virt_text_repeat_linebreak":true,"right_gravity":true,"virt_text":[["▌","OpencodePermissionBorder"]],"ns_id":3,"virt_text_win_col":-2,"priority":4096,"virt_text_hide":false,"virt_text_pos":"win_col"}]],"actions":[],"lines":["----","","","@no-trust run a git status and tell me what files are changed","","[`lua/opencode/ui/formatter.lua`](lua/opencode/ui/formatter.lua)","","**Diagnostics:** (11)","","----","","","** run** `Shows working tree status`","","`````bash","> git status","","`````","","----","",""," Permission Required",""," *bash* `git status`",""," 1. Allow once "," 2. Reject"," 3. Allow always","","Navigate: `j`/`k` or `↑`/`↓` Select: `` or `1-3`","",""],"timestamp":1769449848}
+{
+ "actions": [],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2026-01-05 14:07:54)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_b8e7c60a2001Kisjwk2mVB4dye]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 2,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 3,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 4,
+ 4,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 5,
+ 5,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 6,
+ 6,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 7,
+ 7,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 8,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 9,
+ 10,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-4.1",
+ "OpencodeHint"
+ ],
+ [
+ " (2026-01-05 14:07:54)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_b8e7c60f1001aEWYlAaDRXQ4aJ]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 10,
+ 12,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 11,
+ 13,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 12,
+ 14,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 13,
+ 15,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 14,
+ 16,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 15,
+ 17,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 16,
+ 20,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleSystem"
+ ],
+ [
+ " "
+ ],
+ [
+ "SYSTEM",
+ "OpencodeMessageRoleSystem"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " [permission-display-message]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 17,
+ 22,
+ 0,
+ {
+ "line_hl_group": "OpencodePermissionTitle",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true
+ }
+ ],
+ [
+ 18,
+ 22,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 19,
+ 23,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 20,
+ 24,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 21,
+ 25,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 22,
+ 26,
+ 0,
+ {
+ "line_hl_group": "OpencodeDialogOptionHover",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true
+ }
+ ],
+ [
+ 23,
+ 26,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 24,
+ 26,
+ 2,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "› ",
+ "OpencodeDialogOptionHover"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "overlay",
+ "virt_text_repeat_linebreak": false
+ }
+ ],
+ [
+ 25,
+ 27,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 26,
+ 28,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 27,
+ 29,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 28,
+ 30,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "@no-trust run a git status and tell me what files are changed",
+ "",
+ "[`lua/opencode/ui/formatter.lua`](lua/opencode/ui/formatter.lua)",
+ "",
+ "**Diagnostics:** (11)",
+ "",
+ "----",
+ "",
+ "",
+ "** run** `Shows working tree status`",
+ "",
+ "`````bash",
+ "> git status",
+ "",
+ "`````",
+ "",
+ "----",
+ "",
+ "",
+ " Permission Required",
+ "",
+ " *bash* `git status`",
+ "",
+ " 1. Allow once ",
+ " 2. Reject",
+ " 3. Allow always",
+ "",
+ "Navigate: `j`/`k` or `↑`/`↓` Select: `` or `1-3`",
+ "",
+ ""
+ ],
+ "timestamp": 1770748577
+}
\ No newline at end of file
diff --git a/tests/data/permission-ask-new.json b/tests/data/permission-ask-new.json
index d4e9d979..9b1187ea 100644
--- a/tests/data/permission-ask-new.json
+++ b/tests/data/permission-ask-new.json
@@ -1 +1,282 @@
-[{"properties":{"info":{"title":"New session - 2026-01-05T14:07:52.149Z","version":"1.1.2","directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_47183a8abffeZzOLeJ3j2KV8f8","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","time":{"updated":1767622072149,"created":1767622072149}}},"type":"session.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"info":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"role":"user","id":"msg_b8e7c60a2001Kisjwk2mVB4dye","agent":"build","system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","time":{"created":1767622074530}}},"type":"message.updated"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","id":"prt_b8e7c60a3001M2zsH9REfPdlQt","text":"@no-trust run a git status and tell me what files are changed","messageID":"msg_b8e7c60a2001Kisjwk2mVB4dye"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","id":"prt_b8e7c60a3003Ta9NcXkN0lb0lF","messageID":"msg_b8e7c60a2001Kisjwk2mVB4dye","text":"Called the Read tool with the following input: {\"filePath\":\"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\"}","synthetic":true}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","id":"prt_b8e7c60a7001d3WhKOu2vCR4Cf","messageID":"msg_b8e7c60a2001Kisjwk2mVB4dye","text":"\n00001| local context_module = require('opencode.context')\n00002| local icons = require('opencode.ui.icons')\n00003| local util = require('opencode.util')\n00004| local Output = require('opencode.ui.output')\n00005| local state = require('opencode.state')\n00006| local config = require('opencode.config')\n00007| local snapshot = require('opencode.snapshot')\n00008| local mention = require('opencode.ui.mention')\n00009| \n00010| local M = {}\n00011| \n00012| M.separator = {\n00013| '----',\n00014| '',\n00015| }\n00016| \n00017| ---@param output Output\n00018| ---@param part OpencodeMessagePart\n00019| function M._format_reasoning(output, part)\n00020| local text = vim.trim(part.text or '')\n00021| if text == '' then\n00022| return\n00023| end\n00024| \n00025| local start_line = output:get_line_count() + 1\n00026| \n00027| local title = 'Reasoning'\n00028| local time = part.time\n00029| if time and type(time) == 'table' and time.start then\n00030| local start_text = util.format_time(time.start) or ''\n00031| local end_text = (time['end'] and util.format_time(time['end'])) or nil\n00032| if end_text and end_text ~= '' then\n00033| title = string.format('%s (%s - %s)', title, start_text, end_text)\n00034| elseif start_text ~= '' then\n00035| title = string.format('%s (%s)', title, start_text)\n00036| end\n00037| end\n00038| \n00039| M._format_action(output, icons.get('reasoning') .. ' ' .. title, '')\n00040| \n00041| if config.ui.output.tools.show_reasoning_output then\n00042| output:add_empty_line()\n00043| output:add_lines(vim.split(text, '\\n'))\n00044| output:add_empty_line()\n00045| end\n00046| \n00047| local end_line = output:get_line_count()\n00048| if end_line - start_line > 1 then\n00049| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1, 'OpencodeReasoningText')\n00050| else\n00051| output:add_extmark(start_line - 1, {\n00052| line_hl_group = 'OpencodeReasoningText',\n00053| } --[[@as OutputExtmark]])\n00054| end\n00055| end\n00056| \n00057| function M._handle_permission_request(output, part)\n00058| if part.state and part.state.status == 'error' and part.state.error then\n00059| if part.state.error:match('rejected permission') then\n00060| state.current_permission = nil\n00061| else\n00062| vim.notify('Unknown part state error: ' .. part.state.error)\n00063| end\n00064| return\n00065| end\n00066| \n00067| M._format_permission_request(output)\n00068| end\n00069| \n00070| function M._format_permission_request(output)\n00071| local keys\n00072| \n00073| if require('opencode.ui.ui').is_opencode_focused() then\n00074| keys = {\n00075| config.keymap.permission.accept,\n00076| config.keymap.permission.accept_all,\n00077| config.keymap.permission.deny,\n00078| }\n00079| else\n00080| keys = {\n00081| config.get_key_for_function('editor', 'permission_accept'),\n00082| config.get_key_for_function('editor', 'permission_accept_all'),\n00083| config.get_key_for_function('editor', 'permission_deny'),\n00084| }\n00085| end\n00086| \n00087| output:add_empty_line()\n00088| output:add_line('> [!WARNING] Permission required to run this tool.')\n00089| output:add_line('>')\n00090| output:add_line(('> Accept `%s` Always `%s` Deny `%s`'):format(unpack(keys)))\n00091| output:add_empty_line()\n00092| end\n00093| \n00094| ---Calculate statistics for reverted messages and tool calls\n00095| ---@param messages {info: MessageInfo, parts: OpencodeMessagePart[]}[] All messages in the session\n00096| ---@param revert_index number Index of the message where revert occurred\n00097| ---@param revert_info SessionRevertInfo Revert information\n00098| ---@return {messages: number, tool_calls: number, files: table}\n00099| function M._calculate_revert_stats(messages, revert_index, revert_info)\n00100| local stats = {\n00101| messages = 0,\n00102| tool_calls = 0,\n00103| files = {}, -- { [filename] = { additions = n, deletions = m } }\n00104| }\n00105| \n00106| for i = revert_index, #messages do\n00107| local msg = messages[i]\n00108| if msg.info.role == 'user' then\n00109| stats.messages = stats.messages + 1\n00110| end\n00111| if msg.parts then\n00112| for _, part in ipairs(msg.parts) do\n00113| if part.type == 'tool' then\n00114| stats.tool_calls = stats.tool_calls + 1\n00115| end\n00116| end\n00117| end\n00118| end\n00119| \n00120| if revert_info.diff then\n00121| local current_file = nil\n00122| for line in revert_info.diff:gmatch('[^\\r\\n]+') do\n00123| local file_a = line:match('^%-%-%- ([ab]/.+)')\n00124| local file_b = line:match('^%+%+%+ ([ab]/.+)')\n00125| if file_b then\n00126| current_file = file_b:gsub('^[ab]/', '')\n00127| if not stats.files[current_file] then\n00128| stats.files[current_file] = { additions = 0, deletions = 0 }\n00129| end\n00130| elseif file_a then\n00131| current_file = file_a:gsub('^[ab]/', '')\n00132| if not stats.files[current_file] then\n00133| stats.files[current_file] = { additions = 0, deletions = 0 }\n00134| end\n00135| elseif line:sub(1, 1) == '+' and not line:match('^%+%+%+') then\n00136| if current_file then\n00137| stats.files[current_file].additions = stats.files[current_file].additions + 1\n00138| end\n00139| elseif line:sub(1, 1) == '-' and not line:match('^%-%-%-') then\n00140| if current_file then\n00141| stats.files[current_file].deletions = stats.files[current_file].deletions + 1\n00142| end\n00143| end\n00144| end\n00145| end\n00146| \n00147| return stats\n00148| end\n00149| \n00150| ---Format the revert callout with statistics\n00151| ---@param session_data OpencodeMessage[] All messages in the session\n00152| ---@param start_idx number Index of the message where revert occurred\n00153| ---@return Output output object representing the lines, extmarks, and actions\n00154| function M._format_revert_message(session_data, start_idx)\n00155| local output = Output.new()\n00156| local stats = M._calculate_revert_stats(session_data, start_idx, state.active_session.revert)\n00157| local message_text = stats.messages == 1 and 'message' or 'messages'\n00158| local tool_text = stats.tool_calls == 1 and 'tool call' or 'tool calls'\n00159| \n00160| output:add_lines(M.separator)\n00161| output:add_line(\n00162| string.format('> %d %s reverted, %d %s reverted', stats.messages, message_text, stats.tool_calls, tool_text)\n00163| )\n00164| output:add_line('>')\n00165| output:add_line('> type `/redo` to restore.')\n00166| output:add_empty_line()\n00167| \n00168| if stats.files and next(stats.files) then\n00169| for file, fstats in pairs(stats.files) do\n00170| local file_diff = {}\n00171| if fstats.additions > 0 then\n00172| table.insert(file_diff, '+' .. fstats.additions)\n00173| end\n00174| if fstats.deletions > 0 then\n00175| table.insert(file_diff, '-' .. fstats.deletions)\n00176| end\n00177| if #file_diff > 0 then\n00178| local line_str = string.format(icons.get('file') .. '%s: %s', file, table.concat(file_diff, ' '))\n00179| local line_idx = output:add_line(line_str)\n00180| local col = #(' ' .. file .. ': ')\n00181| for _, diff in ipairs(file_diff) do\n00182| local hl_group = diff:sub(1, 1) == '+' and 'OpencodeDiffAddText' or 'OpencodeDiffDeleteText'\n00183| output:add_extmark(line_idx - 1, {\n00184| virt_text = { { diff, hl_group } },\n00185| virt_text_pos = 'inline',\n00186| virt_text_win_col = col,\n00187| priority = 1000,\n00188| } --[[@as OutputExtmark]])\n00189| col = col + #diff + 1\n00190| end\n00191| end\n00192| end\n00193| end\n00194| return output\n00195| end\n00196| \n00197| local function add_action(output, text, action_type, args, key, line)\n00198| -- actions use api-indexing (e.g. 0 indexed)\n00199| line = (line or output:get_line_count()) - 1\n00200| output:add_action({\n00201| text = text,\n00202| type = action_type,\n00203| args = args,\n00204| key = key,\n00205| display_line = line,\n00206| range = { from = line, to = line },\n00207| })\n00208| end\n00209| \n00210| ---@param output Output Output object to write to\n00211| ---@param part OpencodeMessagePart\n00212| function M._format_patch(output, part)\n00213| if not part.hash then\n00214| return\n00215| end\n00216| \n00217| local restore_points = snapshot.get_restore_points_by_parent(part.hash) or {}\n00218| M._format_action(output, icons.get('snapshot') .. ' Created Snapshot', vim.trim(part.hash:sub(1, 8)))\n00219| \n00220| -- Anchor all snapshot-level actions to the snapshot header line\n00221| add_action(output, '[R]evert file', 'diff_revert_selected_file', { part.hash }, 'R')\n00222| add_action(output, 'Revert [A]ll', 'diff_revert_all', { part.hash }, 'A')\n00223| add_action(output, '[D]iff', 'diff_open', { part.hash }, 'D')\n00224| \n00225| if #restore_points > 0 then\n00226| for _, restore_point in ipairs(restore_points) do\n00227| output:add_line(\n00228| string.format(\n00229| ' %s Restore point `%s` - %s ',\n00230| icons.get('restore_point'),\n00231| vim.trim(restore_point.id:sub(1, 8)),\n00232| util.format_time(restore_point.created_at)\n00233| )\n00234| )\n00235| add_action(output, 'Restore [A]ll', 'diff_restore_snapshot_all', { restore_point.id }, 'A')\n00236| add_action(output, '[R]estore file', 'diff_restore_snapshot_file', { restore_point.id }, 'R')\n00237| end\n00238| end\n00239| end\n00240| \n00241| ---@param output Output Output object to write to\n00242| ---@param message MessageInfo\n00243| function M._format_error(output, message)\n00244| output:add_empty_line()\n00245| M._format_callout(output, 'ERROR', vim.inspect(message.error))\n00246| end\n00247| \n00248| ---@param message OpencodeMessage\n00249| ---@return Output\n00250| function M.format_message_header(message)\n00251| local output = Output.new()\n00252| \n00253| output:add_lines(M.separator)\n00254| local role = message.info.role or 'unknown'\n00255| local icon = message.info.role == 'user' and icons.get('header_user') or icons.get('header_assistant')\n00256| \n00257| local time = message.info.time and message.info.time.created or nil\n00258| local time_text = (time and ' (' .. util.format_time(time) .. ')' or '')\n00259| local role_hl = 'OpencodeMessageRole' .. role:sub(1, 1):upper() .. role:sub(2)\n00260| local model_text = message.info.modelID and ' ' .. message.info.modelID or ''\n00261| \n00262| local debug_text = config.debug.show_ids and ' [' .. message.info.id .. ']' or ''\n00263| \n00264| local display_name\n00265| if role == 'assistant' then\n00266| local mode = message.info.mode\n00267| if mode and mode ~= '' then\n00268| display_name = mode:upper()\n00269| else\n00270| -- For the most recent assistant message, show current_mode if mode is missing\n00271| -- This handles new messages that haven't been stamped yet\n00272| local is_last_message = #state.messages == 0 or message.info.id == state.messages[#state.messages].info.id\n00273| if is_last_message and state.current_mode and state.current_mode ~= '' then\n00274| display_name = state.current_mode:upper()\n00275| else\n00276| display_name = 'ASSISTANT'\n00277| end\n00278| end\n00279| else\n00280| display_name = role:upper()\n00281| end\n00282| \n00283| output:add_extmark(output:get_line_count() - 1, {\n00284| virt_text = {\n00285| { icon, role_hl },\n00286| { ' ' },\n00287| { display_name, role_hl },\n00288| { model_text, 'OpencodeHint' },\n00289| { time_text, 'OpencodeHint' },\n00290| { debug_text, 'OpencodeHint' },\n00291| },\n00292| virt_text_win_col = -3,\n00293| priority = 10,\n00294| } --[[@as OutputExtmark]])\n00295| \n00296| -- Only want to show the error if we have no parts. If we have parts, they'll\n00297| -- handle rendering the error\n00298| if\n00299| role == 'assistant'\n00300| and message.info.error\n00301| and message.info.error ~= ''\n00302| and (not message.parts or #message.parts == 0)\n00303| then\n00304| local error = message.info.error\n00305| local error_message = error.data and error.data.message or vim.inspect(error)\n00306| \n00307| output:add_line('')\n00308| M._format_callout(output, 'ERROR', error_message)\n00309| end\n00310| \n00311| output:add_line('')\n00312| return output\n00313| end\n00314| \n00315| ---@param output Output Output object to write to\n00316| ---@param callout string Callout type (e.g., 'ERROR', 'TODO')\n00317| ---@param text string Callout text content\n00318| ---@param title? string Optional title for the callout\n00319| function M._format_callout(output, callout, text, title)\n00320| title = title and title .. ' ' or ''\n00321| local win_width = (state.windows and state.windows.output_win and vim.api.nvim_win_is_valid(state.windows.output_win))\n00322| and vim.api.nvim_win_get_width(state.windows.output_win)\n00323| or config.ui.window_width\n00324| or 80\n00325| if #text > win_width - 4 then\n00326| local ok, substituted = pcall(vim.fn.substitute, text, '\\v(.{' .. (win_width - 8) .. '})', '\\1\\n', 'g')\n00327| text = ok and substituted or text\n00328| end\n00329| \n00330| -- Trim off any trailing newlines so there isn't an extra line in the\n00331| -- extmarks section\n00332| local lines = vim.split(text:gsub('\\n$', ''), '\\n')\n00333| if #lines == 1 and title == '' then\n00334| output:add_line('> [!' .. callout .. '] ' .. lines[1])\n00335| else\n00336| output:add_line('> [!' .. callout .. ']' .. title)\n00337| output:add_line('>')\n00338| output:add_lines(lines, '> ')\n00339| end\n00340| end\n00341| \n00342| ---@param output Output Output object to write to\n00343| ---@param text string\n00344| ---@param message? OpencodeMessage Optional message object to extract mentions from\n00345| function M._format_user_prompt(output, text, message)\n00346| local start_line = output:get_line_count()\n00347| \n00348| output:add_lines(vim.split(text, '\\n'))\n00349| \n00350| local end_line = output:get_line_count()\n00351| \n00352| local end_line_extmark_offset = 0\n00353| \n00354| local mentions = {}\n00355| if message and message.parts then\n00356| -- message.parts will only be filled out on a re-render\n00357| -- we need to collect the mentions here\n00358| for _, part in ipairs(message.parts) do\n00359| if part.type == 'file' then\n00360| -- we're rerendering this part and we have files, the space after the user prompt\n00361| -- also needs an extmark\n00362| end_line_extmark_offset = 1\n00363| if part.source and part.source.text then\n00364| table.insert(mentions, part.source.text)\n00365| end\n00366| elseif part.type == 'agent' then\n00367| if part.source then\n00368| table.insert(mentions, part.source)\n00369| end\n00370| end\n00371| end\n00372| end\n00373| \n00374| if #mentions > 0 then\n00375| mention.highlight_mentions_in_output(output, text, mentions, start_line)\n00376| end\n00377| \n00378| M._add_vertical_border(output, start_line, end_line + end_line_extmark_offset, 'OpencodeMessageRoleUser', -3)\n00379| end\n00380| \n00381| ---@param output Output Output object to write to\n00382| ---@param part OpencodeMessagePart\n00383| function M._format_selection_context(output, part)\n00384| local json = context_module.decode_json_context(part.text or '', 'selection')\n00385| if not json then\n00386| return\n00387| end\n00388| local start_line = output:get_line_count()\n00389| output:add_lines(vim.split(json.content or '', '\\n'))\n00390| output:add_empty_line()\n00391| \n00392| local end_line = output:get_line_count()\n00393| \n00394| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00395| end\n00396| \n00397| ---@param output Output Output object to write to\n00398| ---@param part OpencodeMessagePart\n00399| function M._format_cursor_data_context(output, part)\n00400| local json = context_module.decode_json_context(part.text or '', 'cursor-data')\n00401| if not json then\n00402| return\n00403| end\n00404| local start_line = output:get_line_count()\n00405| output:add_line('Line ' .. json.line .. ':')\n00406| output:add_lines(vim.split(json.line_content or '', '\\n'))\n00407| output:add_empty_line()\n00408| \n00409| local end_line = output:get_line_count()\n00410| \n00411| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00412| end\n00413| \n00414| ---@param output Output Output object to write to\n00415| ---@param part OpencodeMessagePart\n00416| function M._format_diagnostics_context(output, part)\n00417| local json = context_module.decode_json_context(part.text or '', 'diagnostics')\n00418| if not json then\n00419| return\n00420| end\n00421| local start_line = output:get_line_count()\n00422| local diagnostics = json.content --[[@as OpencodeDiagnostic[] ]]\n00423| if not diagnostics or type(diagnostics) ~= 'table' or #diagnostics == 0 then\n00424| return\n00425| end\n00426| \n00427| local diagnostics_count = { error = 0, warn = 0, info = 0 }\n00428| local diagnostics_icons = {\n00429| error = icons.get('error'),\n00430| warn = icons.get('warning'),\n00431| info = icons.get('info'),\n00432| }\n00433| \n00434| for _, diag in ipairs(diagnostics) do\n00435| local name = vim.diagnostic.severity[diag.severity]:lower()\n00436| diagnostics_count[name] = diagnostics_count[name] + 1\n00437| end\n00438| \n00439| local diag_line = '**Diagnostics:**'\n00440| for name, count in pairs(diagnostics_count) do\n00441| if count > 0 then\n00442| diag_line = diag_line .. (string.format(' %s(%d)', diagnostics_icons[name], count))\n00443| end\n00444| end\n00445| output:add_line(diag_line)\n00446| output:add_empty_line()\n00447| local end_line = output:get_line_count()\n00448| \n00449| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00450| end\n00451| \n00452| ---Format and display the file path in the context\n00453| ---@param output Output Output object to write to\n00454| ---@param path string|nil File path\n00455| function M._format_context_file(output, path)\n00456| if not path or path == '' then\n00457| return\n00458| end\n00459| local cwd = vim.fn.getcwd()\n00460| if vim.startswith(path, cwd) then\n00461| path = path:sub(#cwd + 2)\n00462| end\n00463| return output:add_line(string.format('[%s](%s)', path, path))\n00464| end\n00465| \n00466| ---@param output Output Output object to write to\n00467| ---@param text string\n00468| function M._format_assistant_message(output, text)\n00469| local reference_picker = require('opencode.ui.reference_picker')\n00470| local references = reference_picker.parse_references(text, '')\n00471| \n00472| -- If no references, just add the text as-is\n00473| if #references == 0 then\n00474| output:add_lines(vim.split(text, '\\n'))\n00475| return\n00476| end\n00477| \n00478| -- Sort references by match_start position (ascending)\n00479| table.sort(references, function(a, b)\n00480| return a.match_start < b.match_start\n00481| end)\n00482| \n00483| -- Build a new text with icons inserted before each reference\n00484| local result = ''\n00485| local last_pos = 1\n00486| local ref_icon = icons.get('reference')\n00487| \n00488| for _, ref in ipairs(references) do\n00489| -- Add text before this reference\n00490| result = result .. text:sub(last_pos, ref.match_start - 1)\n00491| -- Add the icon and the reference\n00492| result = result .. ref_icon .. text:sub(ref.match_start, ref.match_end)\n00493| last_pos = ref.match_end + 1\n00494| end\n00495| \n00496| -- Add any remaining text after the last reference\n00497| if last_pos <= #text then\n00498| result = result .. text:sub(last_pos)\n00499| end\n00500| \n00501| output:add_lines(vim.split(result, '\\n'))\n00502| end\n00503| \n00504| ---@param output Output Output object to write to\n00505| ---@param tool_type string Tool type (e.g., 'run', 'read', 'edit', etc.)\n00506| ---@param value string Value associated with the action (e.g., filename, command)\n00507| function M._format_action(output, tool_type, value)\n00508| if not tool_type or not value then\n00509| return\n00510| end\n00511| local line = string.format('**%s** %s', tool_type, value and #value > 0 and ('`' .. value .. '`') or '')\n00512| \n00513| output:add_line(line)\n00514| end\n00515| \n00516| ---@param output Output Output object to write to\n00517| ---@param input BashToolInput data for the tool\n00518| ---@param metadata BashToolMetadata Metadata for the tool use\n00519| function M._format_bash_tool(output, input, metadata)\n00520| M._format_action(output, icons.get('run') .. ' run', input and input.description)\n00521| \n00522| if not config.ui.output.tools.show_output then\n00523| return\n00524| end\n00525| \n00526| if metadata.output or metadata.command or input.command then\n00527| local command = input.command or metadata.command or ''\n00528| local command_output = metadata.output and metadata.output ~= '' and ('\\n' .. metadata.output) or ''\n00529| M._format_code(output, vim.split('> ' .. command .. '\\n' .. command_output, '\\n'), 'bash')\n00530| end\n00531| end\n00532| \n00533| ---@param output Output Output object to write to\n00534| ---@param tool_type string Tool type (e.g., 'read', 'edit', 'write')\n00535| ---@param input FileToolInput data for the tool\n00536| ---@param metadata FileToolMetadata Metadata for the tool use\n00537| function M._format_file_tool(output, tool_type, input, metadata)\n00538| local file_name = input and vim.fn.fnamemodify(input.filePath, ':t') or ''\n00539| local file_type = input and util.get_markdown_filetype(input.filePath) or ''\n00540| local tool_action_icons = { read = icons.get('read'), edit = icons.get('edit'), write = icons.get('write') }\n00541| \n00542| M._format_action(output, tool_action_icons[tool_type] .. ' ' .. tool_type, file_name)\n00543| \n00544| if not config.ui.output.tools.show_output then\n00545| return\n00546| end\n00547| \n00548| if tool_type == 'edit' and metadata.diff then\n00549| M._format_diff(output, metadata.diff, file_type)\n00550| elseif tool_type == 'write' and input and input.content then\n00551| M._format_code(output, vim.split(input.content, '\\n'), file_type)\n00552| end\n00553| end\n00554| \n00555| ---@param output Output Output object to write to\n00556| ---@param title string\n00557| ---@param input TodoToolInput\n00558| function M._format_todo_tool(output, title, input)\n00559| M._format_action(output, icons.get('plan') .. ' plan', (title or ''))\n00560| if not config.ui.output.tools.show_output then\n00561| return\n00562| end\n00563| \n00564| local todos = input and input.todos or {}\n00565| \n00566| for _, item in ipairs(todos) do\n00567| local statuses = { in_progress = '-', completed = 'x', pending = ' ' }\n00568| output:add_line(string.format('- [%s] %s ', statuses[item.status], item.content))\n00569| end\n00570| end\n00571| \n00572| ---@param output Output Output object to write to\n00573| ---@param input GlobToolInput data for the tool\n00574| ---@param metadata GlobToolMetadata Metadata for the tool use\n00575| function M._format_glob_tool(output, input, metadata)\n00576| M._format_action(output, icons.get('search') .. ' glob', input and input.pattern)\n00577| if not config.ui.output.tools.show_output then\n00578| return\n00579| end\n00580| local prefix = metadata.truncated and ' more than' or ''\n00581| output:add_line(string.format('Found%s `%d` file(s):', prefix, metadata.count or 0))\n00582| end\n00583| \n00584| ---@param output Output Output object to write to\n00585| ---@param input GrepToolInput data for the tool\n00586| ---@param metadata GrepToolMetadata Metadata for the tool use\n00587| function M._format_grep_tool(output, input, metadata)\n00588| input = input or { path = '', include = '', pattern = '' }\n00589| \n00590| local grep_str = string.format('%s` `%s', (input.path or input.include) or '', input.pattern or '')\n00591| \n00592| M._format_action(output, icons.get('search') .. ' grep', grep_str)\n00593| if not config.ui.output.tools.show_output then\n00594| return\n00595| end\n00596| local prefix = metadata.truncated and ' more than' or ''\n00597| output:add_line(\n00598| string.format('Found%s `%d` match' .. (metadata.matches ~= 1 and 'es' or ''), prefix, metadata.matches or 0)\n00599| )\n00600| end\n00601| \n00602| ---@param output Output Output object to write to\n00603| ---@param input WebFetchToolInput data for the tool\n00604| function M._format_webfetch_tool(output, input)\n00605| M._format_action(output, icons.get('web') .. ' fetch', input and input.url)\n00606| end\n00607| \n00608| ---@param output Output Output object to write to\n00609| ---@param input ListToolInput\n00610| ---@param metadata ListToolMetadata\n00611| ---@param tool_output string\n00612| function M._format_list_tool(output, input, metadata, tool_output)\n00613| M._format_action(output, icons.get('list') .. ' list', input and input.path or '')\n00614| if not config.ui.output.tools.show_output then\n00615| return\n00616| end\n00617| local lines = vim.split(vim.trim(tool_output or ''), '\\n')\n00618| if #lines < 1 or metadata.count == 0 then\n00619| output:add_line('No files found.')\n00620| return\n00621| end\n00622| if #lines > 1 then\n00623| output:add_line('Files:')\n00624| for i = 2, #lines do\n00625| local file = vim.trim(lines[i])\n00626| if file ~= '' then\n00627| output:add_line(' • ' .. file)\n00628| end\n00629| end\n00630| end\n00631| if metadata.truncated then\n00632| output:add_line(string.format('Results truncated, showing first %d files', metadata.count or '?'))\n00633| end\n00634| end\n00635| \n00636| ---@param output Output Output object to write to\n00637| ---@param part OpencodeMessagePart\n00638| function M._format_tool(output, part)\n00639| local tool = part.tool\n00640| if not tool or not part.state then\n00641| return\n00642| end\n00643| \n00644| local start_line = output:get_line_count() + 1\n00645| local input = part.state.input or {}\n00646| local metadata = part.state.metadata or {}\n00647| local tool_output = part.state.output or ''\n00648| \n00649| if state.current_permission and state.current_permission.messageID == part.messageID then\n00650| metadata = state.current_permission.metadata or metadata\n00651| end\n00652| \n00653| if tool == 'bash' then\n00654| M._format_bash_tool(output, input --[[@as BashToolInput]], metadata --[[@as BashToolMetadata]])\n00655| elseif tool == 'read' or tool == 'edit' or tool == 'write' then\n00656| M._format_file_tool(output, tool, input --[[@as FileToolInput]], metadata --[[@as FileToolMetadata]])\n00657| elseif tool == 'todowrite' then\n00658| M._format_todo_tool(output, part.state.title, input --[[@as TodoToolInput]])\n00659| elseif tool == 'glob' then\n00660| M._format_glob_tool(output, input --[[@as GlobToolInput]], metadata --[[@as GlobToolMetadata]])\n00661| elseif tool == 'list' then\n00662| M._format_list_tool(output, input --[[@as ListToolInput]], metadata --[[@as ListToolMetadata]], tool_output)\n00663| elseif tool == 'grep' then\n00664| M._format_grep_tool(output, input --[[@as GrepToolInput]], metadata --[[@as GrepToolMetadata]])\n00665| elseif tool == 'webfetch' then\n00666| M._format_webfetch_tool(output, input --[[@as WebFetchToolInput]])\n00667| elseif tool == 'task' then\n00668| M._format_task_tool(output, input --[[@as TaskToolInput]], metadata --[[@as TaskToolMetadata]], tool_output)\n00669| else\n00670| M._format_action(output, icons.get('tool') .. ' tool', tool)\n00671| end\n00672| \n00673| if part.state.status == 'error' and part.state.error then\n00674| output:add_line('')\n00675| M._format_callout(output, 'ERROR', part.state.error)\n00676| ---@diagnostic disable-next-line: undefined-field\n00677| elseif part.state.input and part.state.input.error then\n00678| output:add_line('')\n00679| ---I'm not sure about the type with state.input.error\n00680| ---@diagnostic disable-next-line: undefined-field\n00681| M._format_callout(output, 'ERROR', part.state.input.error)\n00682| end\n00683| \n00684| if\n00685| state.current_permission\n00686| and (\n00687| (\n00688| state.current_permission.tool\n00689| and state.current_permission.tool.callID == part.callID\n00690| and state.current_permission.tool.messageID == part.messageID\n00691| )\n00692| ---@TODO this is for backward compatibility, remove later\n00693| or (state.current_permission.messageID == part.messageID and state.current_permission.callID == part.callID)\n00694| )\n00695| then\n00696| M._handle_permission_request(output, part)\n00697| end\n00698| \n00699| local end_line = output:get_line_count()\n00700| if end_line - start_line > 1 then\n00701| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1)\n00702| end\n00703| end\n00704| \n00705| ---@param output Output Output object to write to\n00706| ---@param input TaskToolInput data for the tool\n00707| ---@param metadata TaskToolMetadata Metadata for the tool use\n00708| ---@param tool_output string\n00709| function M._format_task_tool(output, input, metadata, tool_output)\n00710| local start_line = output:get_line_count() + 1\n00711| M._format_action(output, icons.get('task') .. ' task', input and input.description)\n00712| \n00713| if config.ui.output.tools.show_output then\n00714| if tool_output and tool_output ~= '' then\n00715| output:add_empty_line()\n00716| output:add_lines(vim.split(tool_output, '\\n'))\n00717| output:add_empty_line()\n00718| end\n00719| \n00720| if metadata.summary and type(metadata.summary) == 'table' then\n00721| for _, sub_part in ipairs(metadata.summary) do\n00722| if sub_part.type == 'tool' and sub_part.tool then\n00723| M._format_tool(output, sub_part)\n00724| end\n00725| end\n00726| end\n00727| end\n00728| \n00729| local end_line = output:get_line_count()\n00730| output:add_action({\n00731| text = '[S]elect Child Session',\n00732| type = 'select_child_session',\n00733| args = {},\n00734| key = 'S',\n00735| display_line = start_line - 1,\n00736| range = { from = start_line, to = end_line },\n00737| })\n00738| end\n00739| \n00740| ---@param output Output Output object to write to\n00741| ---@param lines string[]\n00742| ---@param language string\n00743| function M._format_code(output, lines, language)\n00744| output:add_empty_line()\n00745| --- NOTE: use longer code fence because lines could contain ```\n00746| output:add_line('`````' .. (language or ''))\n00747| output:add_lines(util.sanitize_lines(lines))\n00748| output:add_line('`````')\n00749| end\n00750| \n00751| ---@param output Output Output object to write to\n00752| ---@param code string\n00753| ---@param file_type string\n00754| function M._format_diff(output, code, file_type)\n00755| output:add_empty_line()\n00756| \n00757| --- NOTE: use longer code fence because code could contain ```\n00758| output:add_line('`````' .. file_type)\n00759| local lines = vim.split(code, '\\n')\n00760| if #lines > 5 then\n00761| lines = vim.list_slice(lines, 6)\n00762| end\n00763| \n00764| for _, line in ipairs(lines) do\n00765| local first_char = line:sub(1, 1)\n00766| if first_char == '+' or first_char == '-' then\n00767| local hl_group = first_char == '+' and 'OpencodeDiffAdd' or 'OpencodeDiffDelete'\n00768| output:add_line(' ' .. line:sub(2))\n00769| local line_idx = output:get_line_count()\n00770| output:add_extmark(line_idx - 1, function()\n00771| return {\n00772| end_col = 0,\n00773| end_row = line_idx,\n00774| virt_text = { { first_char, hl_group } },\n00775| hl_group = hl_group,\n00776| hl_eol = true,\n00777| priority = 5000,\n00778| right_gravity = true,\n00779| end_right_gravity = false,\n00780| virt_text_hide = false,\n00781| virt_text_pos = 'overlay',\n00782| virt_text_repeat_linebreak = false,\n00783| }\n00784| end)\n00785| else\n00786| output:add_line(line)\n00787| end\n00788| end\n00789| output:add_line('`````')\n00790| end\n00791| \n00792| ---@param output Output Output object to write to\n00793| ---@param start_line number\n00794| ---@param end_line number\n00795| ---@param hl_group string Highlight group for the border character\n00796| ---@param win_col number\n00797| ---@param text_hl_group? string Optional highlight group for the background/foreground of text lines\n00798| function M._add_vertical_border(output, start_line, end_line, hl_group, win_col, text_hl_group)\n00799| for line = start_line, end_line do\n00800| local extmark_opts = {\n00801| virt_text = { { require('opencode.ui.icons').get('border'), hl_group } },\n00802| virt_text_pos = 'overlay',\n00803| virt_text_win_col = win_col,\n00804| virt_text_repeat_linebreak = true,\n00805| }\n00806| \n00807| -- Add line highlight if text_hl_group is provided\n00808| if text_hl_group then\n00809| extmark_opts.line_hl_group = text_hl_group\n00810| end\n00811| \n00812| output:add_extmark(line - 1, extmark_opts --[[@as OutputExtmark]])\n00813| end\n00814| end\n00815| \n00816| ---Formats a single message part and returns the resulting output object\n00817| ---@param part OpencodeMessagePart The part to format\n00818| ---@param message? OpencodeMessage Optional message object to extract role and mentions from\n00819| ---@param is_last_part? boolean Whether this is the last part in the message, used to show an error if there is one\n00820| ---@return Output\n00821| function M.format_part(part, message, is_last_part)\n00822| local output = Output.new()\n00823| \n00824| if not message or not message.info or not message.info.role then\n00825| return output\n00826| end\n00827| \n00828| local content_added = false\n00829| local role = message.info.role\n00830| \n00831| if role == 'user' then\n00832| if part.type == 'text' and part.text then\n00833| if part.synthetic == true then\n00834| M._format_selection_context(output, part)\n00835| M._format_cursor_data_context(output, part)\n00836| M._format_diagnostics_context(output, part)\n00837| else\n00838| M._format_user_prompt(output, vim.trim(part.text), message)\n00839| content_added = true\n00840| end\n00841| elseif part.type == 'file' then\n00842| local file_line = M._format_context_file(output, part.filename)\n00843| if file_line then\n00844| M._add_vertical_border(output, file_line - 1, file_line, 'OpencodeMessageRoleUser', -3)\n00845| content_added = true\n00846| end\n00847| end\n00848| elseif role == 'assistant' then\n00849| if part.type == 'text' and part.text then\n00850| M._format_assistant_message(output, vim.trim(part.text))\n00851| content_added = true\n00852| elseif part.type == 'reasoning' and part.text then\n00853| M._format_reasoning(output, part)\n00854| content_added = true\n00855| elseif part.type == 'tool' then\n00856| M._format_tool(output, part)\n00857| content_added = true\n00858| elseif part.type == 'patch' and part.hash then\n00859| M._format_patch(output, part)\n00860| content_added = true\n00861| end\n00862| end\n00863| \n00864| if content_added then\n00865| output:add_empty_line()\n00866| end\n00867| \n00868| if is_last_part and role == 'assistant' and message.info.error and message.info.error ~= '' then\n00869| local error = message.info.error\n00870| local error_message = error.data and error.data.message or vim.inspect(error)\n00871| M._format_callout(output, 'ERROR', error_message)\n00872| output:add_empty_line()\n00873| end\n00874| \n00875| return output\n00876| end\n00877| \n00878| return M\n00879| \n\n(End of file - total 879 lines)\n","synthetic":true}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"file","url":"file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua","id":"prt_b8e7c60a7002ybV09VDHoQQeO7","filename":"lua/opencode/ui/formatter.lua","messageID":"msg_b8e7c60a2001Kisjwk2mVB4dye","mime":"text/plain"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"text","id":"prt_b8e7c60a3002XHHlk77vAPApvR","messageID":"msg_b8e7c60a2001Kisjwk2mVB4dye","text":"{\"content\":[{\"msg\":\"expected `SessionRevertInfo` but found `SessionRevertInfo?`.\",\"severity\":2,\"pos\":\"l156:c68\"},{\"msg\":\"expected `integer?` but found `number`.\",\"severity\":2,\"pos\":\"l490:c43\"},{\"msg\":\"expected `integer` but found `number`.\",\"severity\":2,\"pos\":\"l492:c45\"},{\"msg\":\"expected `integer?` but found `number`.\",\"severity\":2,\"pos\":\"l492:c62\"},{\"msg\":\"state.active_session may be nil\",\"severity\":2,\"pos\":\"l156:c68\"},{\"msg\":\"state.messages[#state.messages] may be nil\",\"severity\":2,\"pos\":\"l272:c74\"},{\"msg\":\"state.messages may be nil\",\"severity\":2,\"pos\":\"l272:c74\"},{\"msg\":\"Undefined field `[diag.severity]`.\",\"severity\":2,\"pos\":\"l435:c42\"},{\"msg\":\"Undefined field `command`.\",\"severity\":2,\"pos\":\"l526:c34\"},{\"msg\":\"Undefined field `command`.\",\"severity\":2,\"pos\":\"l527:c47\"},{\"msg\":\"Cannot assign `number` to `integer`.\",\"severity\":2,\"pos\":\"l493:c5\"}],\"context_type\":\"diagnostics\"}","synthetic":true}},"type":"message.part.updated"},{"properties":{"info":{"title":"New session - 2026-01-05T14:07:52.149Z","version":"1.1.2","directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_47183a8abffeZzOLeJ3j2KV8f8","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","time":{"updated":1767622074603,"created":1767622072149}}},"type":"session.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"info":{"providerID":"github-copilot","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"agent":"build","time":{"created":1767622074609},"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","mode":"build","modelID":"gpt-4.1","id":"msg_b8e7c60f1001aEWYlAaDRXQ4aJ","parentID":"msg_b8e7c60a2001Kisjwk2mVB4dye","cost":0,"tokens":{"output":0,"reasoning":0,"input":0,"cache":{"write":0,"read":0}}}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","time":{"created":1767622074530},"model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"role":"user","id":"msg_b8e7c60a2001Kisjwk2mVB4dye","agent":"build","system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","summary":{"diffs":[]}}},"type":"message.updated"},{"properties":{"info":{"title":"New session - 2026-01-05T14:07:52.149Z","version":"1.1.2","directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_47183a8abffeZzOLeJ3j2KV8f8","time":{"updated":1767622074670,"created":1767622072149},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","summary":{"deletions":0,"additions":0,"files":0}}},"type":"session.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"step-start","id":"prt_b8e7c6672001F10WAiQKbzNEtE","snapshot":"5ba6e95774829e7f501299039b72b72dc32c6620","messageID":"msg_b8e7c60f1001aEWYlAaDRXQ4aJ"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"tool","messageID":"msg_b8e7c60f1001aEWYlAaDRXQ4aJ","id":"prt_b8e7c6686001cCV44vsFtbpF42","state":{"status":"pending","input":{},"raw":""},"callID":"call_KAC0LdAxKEbU6HTAPH5QJfGx","tool":"bash"}},"type":"message.part.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"part":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","type":"tool","messageID":"msg_b8e7c60f1001aEWYlAaDRXQ4aJ","id":"prt_b8e7c6686001cCV44vsFtbpF42","state":{"status":"running","input":{"description":"Shows working tree status","command":"git status"},"time":{"start":1767622076189}},"callID":"call_KAC0LdAxKEbU6HTAPH5QJfGx","tool":"bash"}},"type":"message.part.updated"},{"properties":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","tool":{"messageID":"msg_b8e7c60f1001aEWYlAaDRXQ4aJ","callID":"call_KAC0LdAxKEbU6HTAPH5QJfGx"},"patterns":["git status"],"id":"per_b8e7c6744001DX6EZ9KHM15RLi","permission":"bash","always":["git status*"],"metadata":{}},"type":"permission.asked"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"info":{"sessionID":"ses_47183a8abffeZzOLeJ3j2KV8f8","time":{"created":1767622074530},"model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"role":"user","id":"msg_b8e7c60a2001Kisjwk2mVB4dye","agent":"build","system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","summary":{"title":"Running git status to list changed files","diffs":[]}}},"type":"message.updated"},{"properties":[],"type":"custom.emit_events.finished"},{"properties":{"info":{"title":"Running git status for formatter.lua changes","version":"1.1.2","directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_47183a8abffeZzOLeJ3j2KV8f8","time":{"updated":1767622082619,"created":1767622072149},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","summary":{"deletions":0,"additions":0,"files":0}}},"type":"session.updated"},{"properties":[],"type":"custom.emit_events.finished"}]
+[
+ {
+ "properties": {
+ "info": {
+ "title": "New session - 2026-01-05T14:07:52.149Z",
+ "version": "1.1.2",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "time": { "updated": 1767622072149, "created": 1767622072149 }
+ }
+ },
+ "type": "session.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "role": "user",
+ "id": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "agent": "build",
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "time": { "created": 1767622074530 }
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "id": "prt_b8e7c60a3001M2zsH9REfPdlQt",
+ "text": "@no-trust run a git status and tell me what files are changed",
+ "messageID": "msg_b8e7c60a2001Kisjwk2mVB4dye"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "id": "prt_b8e7c60a3003Ta9NcXkN0lb0lF",
+ "messageID": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "text": "Called the Read tool with the following input: {\"filePath\":\"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua\"}",
+ "synthetic": true
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "id": "prt_b8e7c60a7001d3WhKOu2vCR4Cf",
+ "messageID": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "text": "\n00001| local context_module = require('opencode.context')\n00002| local icons = require('opencode.ui.icons')\n00003| local util = require('opencode.util')\n00004| local Output = require('opencode.ui.output')\n00005| local state = require('opencode.state')\n00006| local config = require('opencode.config')\n00007| local snapshot = require('opencode.snapshot')\n00008| local mention = require('opencode.ui.mention')\n00009| \n00010| local M = {}\n00011| \n00012| M.separator = {\n00013| '----',\n00014| '',\n00015| }\n00016| \n00017| ---@param output Output\n00018| ---@param part OpencodeMessagePart\n00019| function M._format_reasoning(output, part)\n00020| local text = vim.trim(part.text or '')\n00021| if text == '' then\n00022| return\n00023| end\n00024| \n00025| local start_line = output:get_line_count() + 1\n00026| \n00027| local title = 'Reasoning'\n00028| local time = part.time\n00029| if time and type(time) == 'table' and time.start then\n00030| local start_text = util.format_time(time.start) or ''\n00031| local end_text = (time['end'] and util.format_time(time['end'])) or nil\n00032| if end_text and end_text ~= '' then\n00033| title = string.format('%s (%s - %s)', title, start_text, end_text)\n00034| elseif start_text ~= '' then\n00035| title = string.format('%s (%s)', title, start_text)\n00036| end\n00037| end\n00038| \n00039| M._format_action(output, icons.get('reasoning') .. ' ' .. title, '')\n00040| \n00041| if config.ui.output.tools.show_reasoning_output then\n00042| output:add_empty_line()\n00043| output:add_lines(vim.split(text, '\\n'))\n00044| output:add_empty_line()\n00045| end\n00046| \n00047| local end_line = output:get_line_count()\n00048| if end_line - start_line > 1 then\n00049| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1, 'OpencodeReasoningText')\n00050| else\n00051| output:add_extmark(start_line - 1, {\n00052| line_hl_group = 'OpencodeReasoningText',\n00053| } --[[@as OutputExtmark]])\n00054| end\n00055| end\n00056| \n00057| function M._handle_permission_request(output, part)\n00058| if part.state and part.state.status == 'error' and part.state.error then\n00059| if part.state.error:match('rejected permission') then\n00060| state.current_permission = nil\n00061| else\n00062| vim.notify('Unknown part state error: ' .. part.state.error)\n00063| end\n00064| return\n00065| end\n00066| \n00067| M._format_permission_request(output)\n00068| end\n00069| \n00070| function M._format_permission_request(output)\n00071| local keys\n00072| \n00073| if require('opencode.ui.ui').is_opencode_focused() then\n00074| keys = {\n00075| config.keymap.permission.accept,\n00076| config.keymap.permission.accept_all,\n00077| config.keymap.permission.deny,\n00078| }\n00079| else\n00080| keys = {\n00081| config.get_key_for_function('editor', 'permission_accept'),\n00082| config.get_key_for_function('editor', 'permission_accept_all'),\n00083| config.get_key_for_function('editor', 'permission_deny'),\n00084| }\n00085| end\n00086| \n00087| output:add_empty_line()\n00088| output:add_line('> [!WARNING] Permission required to run this tool.')\n00089| output:add_line('>')\n00090| output:add_line(('> Accept `%s` Always `%s` Deny `%s`'):format(unpack(keys)))\n00091| output:add_empty_line()\n00092| end\n00093| \n00094| ---Calculate statistics for reverted messages and tool calls\n00095| ---@param messages {info: MessageInfo, parts: OpencodeMessagePart[]}[] All messages in the session\n00096| ---@param revert_index number Index of the message where revert occurred\n00097| ---@param revert_info SessionRevertInfo Revert information\n00098| ---@return {messages: number, tool_calls: number, files: table}\n00099| function M._calculate_revert_stats(messages, revert_index, revert_info)\n00100| local stats = {\n00101| messages = 0,\n00102| tool_calls = 0,\n00103| files = {}, -- { [filename] = { additions = n, deletions = m } }\n00104| }\n00105| \n00106| for i = revert_index, #messages do\n00107| local msg = messages[i]\n00108| if msg.info.role == 'user' then\n00109| stats.messages = stats.messages + 1\n00110| end\n00111| if msg.parts then\n00112| for _, part in ipairs(msg.parts) do\n00113| if part.type == 'tool' then\n00114| stats.tool_calls = stats.tool_calls + 1\n00115| end\n00116| end\n00117| end\n00118| end\n00119| \n00120| if revert_info.diff then\n00121| local current_file = nil\n00122| for line in revert_info.diff:gmatch('[^\\r\\n]+') do\n00123| local file_a = line:match('^%-%-%- ([ab]/.+)')\n00124| local file_b = line:match('^%+%+%+ ([ab]/.+)')\n00125| if file_b then\n00126| current_file = file_b:gsub('^[ab]/', '')\n00127| if not stats.files[current_file] then\n00128| stats.files[current_file] = { additions = 0, deletions = 0 }\n00129| end\n00130| elseif file_a then\n00131| current_file = file_a:gsub('^[ab]/', '')\n00132| if not stats.files[current_file] then\n00133| stats.files[current_file] = { additions = 0, deletions = 0 }\n00134| end\n00135| elseif line:sub(1, 1) == '+' and not line:match('^%+%+%+') then\n00136| if current_file then\n00137| stats.files[current_file].additions = stats.files[current_file].additions + 1\n00138| end\n00139| elseif line:sub(1, 1) == '-' and not line:match('^%-%-%-') then\n00140| if current_file then\n00141| stats.files[current_file].deletions = stats.files[current_file].deletions + 1\n00142| end\n00143| end\n00144| end\n00145| end\n00146| \n00147| return stats\n00148| end\n00149| \n00150| ---Format the revert callout with statistics\n00151| ---@param session_data OpencodeMessage[] All messages in the session\n00152| ---@param start_idx number Index of the message where revert occurred\n00153| ---@return Output output object representing the lines, extmarks, and actions\n00154| function M._format_revert_message(session_data, start_idx)\n00155| local output = Output.new()\n00156| local stats = M._calculate_revert_stats(session_data, start_idx, state.active_session.revert)\n00157| local message_text = stats.messages == 1 and 'message' or 'messages'\n00158| local tool_text = stats.tool_calls == 1 and 'tool call' or 'tool calls'\n00159| \n00160| output:add_lines(M.separator)\n00161| output:add_line(\n00162| string.format('> %d %s reverted, %d %s reverted', stats.messages, message_text, stats.tool_calls, tool_text)\n00163| )\n00164| output:add_line('>')\n00165| output:add_line('> type `/redo` to restore.')\n00166| output:add_empty_line()\n00167| \n00168| if stats.files and next(stats.files) then\n00169| for file, fstats in pairs(stats.files) do\n00170| local file_diff = {}\n00171| if fstats.additions > 0 then\n00172| table.insert(file_diff, '+' .. fstats.additions)\n00173| end\n00174| if fstats.deletions > 0 then\n00175| table.insert(file_diff, '-' .. fstats.deletions)\n00176| end\n00177| if #file_diff > 0 then\n00178| local line_str = string.format(icons.get('file') .. '%s: %s', file, table.concat(file_diff, ' '))\n00179| local line_idx = output:add_line(line_str)\n00180| local col = #(' ' .. file .. ': ')\n00181| for _, diff in ipairs(file_diff) do\n00182| local hl_group = diff:sub(1, 1) == '+' and 'OpencodeDiffAddText' or 'OpencodeDiffDeleteText'\n00183| output:add_extmark(line_idx - 1, {\n00184| virt_text = { { diff, hl_group } },\n00185| virt_text_pos = 'inline',\n00186| virt_text_win_col = col,\n00187| priority = 1000,\n00188| } --[[@as OutputExtmark]])\n00189| col = col + #diff + 1\n00190| end\n00191| end\n00192| end\n00193| end\n00194| return output\n00195| end\n00196| \n00197| local function add_action(output, text, action_type, args, key, line)\n00198| -- actions use api-indexing (e.g. 0 indexed)\n00199| line = (line or output:get_line_count()) - 1\n00200| output:add_action({\n00201| text = text,\n00202| type = action_type,\n00203| args = args,\n00204| key = key,\n00205| display_line = line,\n00206| range = { from = line, to = line },\n00207| })\n00208| end\n00209| \n00210| ---@param output Output Output object to write to\n00211| ---@param part OpencodeMessagePart\n00212| function M._format_patch(output, part)\n00213| if not part.hash then\n00214| return\n00215| end\n00216| \n00217| local restore_points = snapshot.get_restore_points_by_parent(part.hash) or {}\n00218| M._format_action(output, icons.get('snapshot') .. ' Created Snapshot', vim.trim(part.hash:sub(1, 8)))\n00219| \n00220| -- Anchor all snapshot-level actions to the snapshot header line\n00221| add_action(output, '[R]evert file', 'diff_revert_selected_file', { part.hash }, 'R')\n00222| add_action(output, 'Revert [A]ll', 'diff_revert_all', { part.hash }, 'A')\n00223| add_action(output, '[D]iff', 'diff_open', { part.hash }, 'D')\n00224| \n00225| if #restore_points > 0 then\n00226| for _, restore_point in ipairs(restore_points) do\n00227| output:add_line(\n00228| string.format(\n00229| ' %s Restore point `%s` - %s ',\n00230| icons.get('restore_point'),\n00231| vim.trim(restore_point.id:sub(1, 8)),\n00232| util.format_time(restore_point.created_at)\n00233| )\n00234| )\n00235| add_action(output, 'Restore [A]ll', 'diff_restore_snapshot_all', { restore_point.id }, 'A')\n00236| add_action(output, '[R]estore file', 'diff_restore_snapshot_file', { restore_point.id }, 'R')\n00237| end\n00238| end\n00239| end\n00240| \n00241| ---@param output Output Output object to write to\n00242| ---@param message MessageInfo\n00243| function M._format_error(output, message)\n00244| output:add_empty_line()\n00245| M._format_callout(output, 'ERROR', vim.inspect(message.error))\n00246| end\n00247| \n00248| ---@param message OpencodeMessage\n00249| ---@return Output\n00250| function M.format_message_header(message)\n00251| local output = Output.new()\n00252| \n00253| output:add_lines(M.separator)\n00254| local role = message.info.role or 'unknown'\n00255| local icon = message.info.role == 'user' and icons.get('header_user') or icons.get('header_assistant')\n00256| \n00257| local time = message.info.time and message.info.time.created or nil\n00258| local time_text = (time and ' (' .. util.format_time(time) .. ')' or '')\n00259| local role_hl = 'OpencodeMessageRole' .. role:sub(1, 1):upper() .. role:sub(2)\n00260| local model_text = message.info.modelID and ' ' .. message.info.modelID or ''\n00261| \n00262| local debug_text = config.debug.show_ids and ' [' .. message.info.id .. ']' or ''\n00263| \n00264| local display_name\n00265| if role == 'assistant' then\n00266| local mode = message.info.mode\n00267| if mode and mode ~= '' then\n00268| display_name = mode:upper()\n00269| else\n00270| -- For the most recent assistant message, show current_mode if mode is missing\n00271| -- This handles new messages that haven't been stamped yet\n00272| local is_last_message = #state.messages == 0 or message.info.id == state.messages[#state.messages].info.id\n00273| if is_last_message and state.current_mode and state.current_mode ~= '' then\n00274| display_name = state.current_mode:upper()\n00275| else\n00276| display_name = 'ASSISTANT'\n00277| end\n00278| end\n00279| else\n00280| display_name = role:upper()\n00281| end\n00282| \n00283| output:add_extmark(output:get_line_count() - 1, {\n00284| virt_text = {\n00285| { icon, role_hl },\n00286| { ' ' },\n00287| { display_name, role_hl },\n00288| { model_text, 'OpencodeHint' },\n00289| { time_text, 'OpencodeHint' },\n00290| { debug_text, 'OpencodeHint' },\n00291| },\n00292| virt_text_win_col = -3,\n00293| priority = 10,\n00294| } --[[@as OutputExtmark]])\n00295| \n00296| -- Only want to show the error if we have no parts. If we have parts, they'll\n00297| -- handle rendering the error\n00298| if\n00299| role == 'assistant'\n00300| and message.info.error\n00301| and message.info.error ~= ''\n00302| and (not message.parts or #message.parts == 0)\n00303| then\n00304| local error = message.info.error\n00305| local error_message = error.data and error.data.message or vim.inspect(error)\n00306| \n00307| output:add_line('')\n00308| M._format_callout(output, 'ERROR', error_message)\n00309| end\n00310| \n00311| output:add_line('')\n00312| return output\n00313| end\n00314| \n00315| ---@param output Output Output object to write to\n00316| ---@param callout string Callout type (e.g., 'ERROR', 'TODO')\n00317| ---@param text string Callout text content\n00318| ---@param title? string Optional title for the callout\n00319| function M._format_callout(output, callout, text, title)\n00320| title = title and title .. ' ' or ''\n00321| local win_width = (state.windows and state.windows.output_win and vim.api.nvim_win_is_valid(state.windows.output_win))\n00322| and vim.api.nvim_win_get_width(state.windows.output_win)\n00323| or config.ui.window_width\n00324| or 80\n00325| if #text > win_width - 4 then\n00326| local ok, substituted = pcall(vim.fn.substitute, text, '\\v(.{' .. (win_width - 8) .. '})', '\\1\\n', 'g')\n00327| text = ok and substituted or text\n00328| end\n00329| \n00330| -- Trim off any trailing newlines so there isn't an extra line in the\n00331| -- extmarks section\n00332| local lines = vim.split(text:gsub('\\n$', ''), '\\n')\n00333| if #lines == 1 and title == '' then\n00334| output:add_line('> [!' .. callout .. '] ' .. lines[1])\n00335| else\n00336| output:add_line('> [!' .. callout .. ']' .. title)\n00337| output:add_line('>')\n00338| output:add_lines(lines, '> ')\n00339| end\n00340| end\n00341| \n00342| ---@param output Output Output object to write to\n00343| ---@param text string\n00344| ---@param message? OpencodeMessage Optional message object to extract mentions from\n00345| function M._format_user_prompt(output, text, message)\n00346| local start_line = output:get_line_count()\n00347| \n00348| output:add_lines(vim.split(text, '\\n'))\n00349| \n00350| local end_line = output:get_line_count()\n00351| \n00352| local end_line_extmark_offset = 0\n00353| \n00354| local mentions = {}\n00355| if message and message.parts then\n00356| -- message.parts will only be filled out on a re-render\n00357| -- we need to collect the mentions here\n00358| for _, part in ipairs(message.parts) do\n00359| if part.type == 'file' then\n00360| -- we're rerendering this part and we have files, the space after the user prompt\n00361| -- also needs an extmark\n00362| end_line_extmark_offset = 1\n00363| if part.source and part.source.text then\n00364| table.insert(mentions, part.source.text)\n00365| end\n00366| elseif part.type == 'agent' then\n00367| if part.source then\n00368| table.insert(mentions, part.source)\n00369| end\n00370| end\n00371| end\n00372| end\n00373| \n00374| if #mentions > 0 then\n00375| mention.highlight_mentions_in_output(output, text, mentions, start_line)\n00376| end\n00377| \n00378| M._add_vertical_border(output, start_line, end_line + end_line_extmark_offset, 'OpencodeMessageRoleUser', -3)\n00379| end\n00380| \n00381| ---@param output Output Output object to write to\n00382| ---@param part OpencodeMessagePart\n00383| function M._format_selection_context(output, part)\n00384| local json = context_module.decode_json_context(part.text or '', 'selection')\n00385| if not json then\n00386| return\n00387| end\n00388| local start_line = output:get_line_count()\n00389| output:add_lines(vim.split(json.content or '', '\\n'))\n00390| output:add_empty_line()\n00391| \n00392| local end_line = output:get_line_count()\n00393| \n00394| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00395| end\n00396| \n00397| ---@param output Output Output object to write to\n00398| ---@param part OpencodeMessagePart\n00399| function M._format_cursor_data_context(output, part)\n00400| local json = context_module.decode_json_context(part.text or '', 'cursor-data')\n00401| if not json then\n00402| return\n00403| end\n00404| local start_line = output:get_line_count()\n00405| output:add_line('Line ' .. json.line .. ':')\n00406| output:add_lines(vim.split(json.line_content or '', '\\n'))\n00407| output:add_empty_line()\n00408| \n00409| local end_line = output:get_line_count()\n00410| \n00411| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00412| end\n00413| \n00414| ---@param output Output Output object to write to\n00415| ---@param part OpencodeMessagePart\n00416| function M._format_diagnostics_context(output, part)\n00417| local json = context_module.decode_json_context(part.text or '', 'diagnostics')\n00418| if not json then\n00419| return\n00420| end\n00421| local start_line = output:get_line_count()\n00422| local diagnostics = json.content --[[@as OpencodeDiagnostic[] ]]\n00423| if not diagnostics or type(diagnostics) ~= 'table' or #diagnostics == 0 then\n00424| return\n00425| end\n00426| \n00427| local diagnostics_count = { error = 0, warn = 0, info = 0 }\n00428| local diagnostics_icons = {\n00429| error = icons.get('error'),\n00430| warn = icons.get('warning'),\n00431| info = icons.get('info'),\n00432| }\n00433| \n00434| for _, diag in ipairs(diagnostics) do\n00435| local name = vim.diagnostic.severity[diag.severity]:lower()\n00436| diagnostics_count[name] = diagnostics_count[name] + 1\n00437| end\n00438| \n00439| local diag_line = '**Diagnostics:**'\n00440| for name, count in pairs(diagnostics_count) do\n00441| if count > 0 then\n00442| diag_line = diag_line .. (string.format(' %s(%d)', diagnostics_icons[name], count))\n00443| end\n00444| end\n00445| output:add_line(diag_line)\n00446| output:add_empty_line()\n00447| local end_line = output:get_line_count()\n00448| \n00449| M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3)\n00450| end\n00451| \n00452| ---Format and display the file path in the context\n00453| ---@param output Output Output object to write to\n00454| ---@param path string|nil File path\n00455| function M._format_context_file(output, path)\n00456| if not path or path == '' then\n00457| return\n00458| end\n00459| local cwd = vim.fn.getcwd()\n00460| if vim.startswith(path, cwd) then\n00461| path = path:sub(#cwd + 2)\n00462| end\n00463| return output:add_line(string.format('[%s](%s)', path, path))\n00464| end\n00465| \n00466| ---@param output Output Output object to write to\n00467| ---@param text string\n00468| function M._format_assistant_message(output, text)\n00469| local reference_picker = require('opencode.ui.reference_picker')\n00470| local references = reference_picker.parse_references(text, '')\n00471| \n00472| -- If no references, just add the text as-is\n00473| if #references == 0 then\n00474| output:add_lines(vim.split(text, '\\n'))\n00475| return\n00476| end\n00477| \n00478| -- Sort references by match_start position (ascending)\n00479| table.sort(references, function(a, b)\n00480| return a.match_start < b.match_start\n00481| end)\n00482| \n00483| -- Build a new text with icons inserted before each reference\n00484| local result = ''\n00485| local last_pos = 1\n00486| local ref_icon = icons.get('reference')\n00487| \n00488| for _, ref in ipairs(references) do\n00489| -- Add text before this reference\n00490| result = result .. text:sub(last_pos, ref.match_start - 1)\n00491| -- Add the icon and the reference\n00492| result = result .. ref_icon .. text:sub(ref.match_start, ref.match_end)\n00493| last_pos = ref.match_end + 1\n00494| end\n00495| \n00496| -- Add any remaining text after the last reference\n00497| if last_pos <= #text then\n00498| result = result .. text:sub(last_pos)\n00499| end\n00500| \n00501| output:add_lines(vim.split(result, '\\n'))\n00502| end\n00503| \n00504| ---@param output Output Output object to write to\n00505| ---@param tool_type string Tool type (e.g., 'run', 'read', 'edit', etc.)\n00506| ---@param value string Value associated with the action (e.g., filename, command)\n00507| function M._format_action(output, tool_type, value)\n00508| if not tool_type or not value then\n00509| return\n00510| end\n00511| local line = string.format('**%s** %s', tool_type, value and #value > 0 and ('`' .. value .. '`') or '')\n00512| \n00513| output:add_line(line)\n00514| end\n00515| \n00516| ---@param output Output Output object to write to\n00517| ---@param input BashToolInput data for the tool\n00518| ---@param metadata BashToolMetadata Metadata for the tool use\n00519| function M._format_bash_tool(output, input, metadata)\n00520| M._format_action(output, icons.get('run') .. ' run', input and input.description)\n00521| \n00522| if not config.ui.output.tools.show_output then\n00523| return\n00524| end\n00525| \n00526| if metadata.output or metadata.command or input.command then\n00527| local command = input.command or metadata.command or ''\n00528| local command_output = metadata.output and metadata.output ~= '' and ('\\n' .. metadata.output) or ''\n00529| M._format_code(output, vim.split('> ' .. command .. '\\n' .. command_output, '\\n'), 'bash')\n00530| end\n00531| end\n00532| \n00533| ---@param output Output Output object to write to\n00534| ---@param tool_type string Tool type (e.g., 'read', 'edit', 'write')\n00535| ---@param input FileToolInput data for the tool\n00536| ---@param metadata FileToolMetadata Metadata for the tool use\n00537| function M._format_file_tool(output, tool_type, input, metadata)\n00538| local file_name = input and vim.fn.fnamemodify(input.filePath, ':t') or ''\n00539| local file_type = input and util.get_markdown_filetype(input.filePath) or ''\n00540| local tool_action_icons = { read = icons.get('read'), edit = icons.get('edit'), write = icons.get('write') }\n00541| \n00542| M._format_action(output, tool_action_icons[tool_type] .. ' ' .. tool_type, file_name)\n00543| \n00544| if not config.ui.output.tools.show_output then\n00545| return\n00546| end\n00547| \n00548| if tool_type == 'edit' and metadata.diff then\n00549| M._format_diff(output, metadata.diff, file_type)\n00550| elseif tool_type == 'write' and input and input.content then\n00551| M._format_code(output, vim.split(input.content, '\\n'), file_type)\n00552| end\n00553| end\n00554| \n00555| ---@param output Output Output object to write to\n00556| ---@param title string\n00557| ---@param input TodoToolInput\n00558| function M._format_todo_tool(output, title, input)\n00559| M._format_action(output, icons.get('plan') .. ' plan', (title or ''))\n00560| if not config.ui.output.tools.show_output then\n00561| return\n00562| end\n00563| \n00564| local todos = input and input.todos or {}\n00565| \n00566| for _, item in ipairs(todos) do\n00567| local statuses = { in_progress = '-', completed = 'x', pending = ' ' }\n00568| output:add_line(string.format('- [%s] %s ', statuses[item.status], item.content))\n00569| end\n00570| end\n00571| \n00572| ---@param output Output Output object to write to\n00573| ---@param input GlobToolInput data for the tool\n00574| ---@param metadata GlobToolMetadata Metadata for the tool use\n00575| function M._format_glob_tool(output, input, metadata)\n00576| M._format_action(output, icons.get('search') .. ' glob', input and input.pattern)\n00577| if not config.ui.output.tools.show_output then\n00578| return\n00579| end\n00580| local prefix = metadata.truncated and ' more than' or ''\n00581| output:add_line(string.format('Found%s `%d` file(s):', prefix, metadata.count or 0))\n00582| end\n00583| \n00584| ---@param output Output Output object to write to\n00585| ---@param input GrepToolInput data for the tool\n00586| ---@param metadata GrepToolMetadata Metadata for the tool use\n00587| function M._format_grep_tool(output, input, metadata)\n00588| input = input or { path = '', include = '', pattern = '' }\n00589| \n00590| local grep_str = string.format('%s` `%s', (input.path or input.include) or '', input.pattern or '')\n00591| \n00592| M._format_action(output, icons.get('search') .. ' grep', grep_str)\n00593| if not config.ui.output.tools.show_output then\n00594| return\n00595| end\n00596| local prefix = metadata.truncated and ' more than' or ''\n00597| output:add_line(\n00598| string.format('Found%s `%d` match' .. (metadata.matches ~= 1 and 'es' or ''), prefix, metadata.matches or 0)\n00599| )\n00600| end\n00601| \n00602| ---@param output Output Output object to write to\n00603| ---@param input WebFetchToolInput data for the tool\n00604| function M._format_webfetch_tool(output, input)\n00605| M._format_action(output, icons.get('web') .. ' fetch', input and input.url)\n00606| end\n00607| \n00608| ---@param output Output Output object to write to\n00609| ---@param input ListToolInput\n00610| ---@param metadata ListToolMetadata\n00611| ---@param tool_output string\n00612| function M._format_list_tool(output, input, metadata, tool_output)\n00613| M._format_action(output, icons.get('list') .. ' list', input and input.path or '')\n00614| if not config.ui.output.tools.show_output then\n00615| return\n00616| end\n00617| local lines = vim.split(vim.trim(tool_output or ''), '\\n')\n00618| if #lines < 1 or metadata.count == 0 then\n00619| output:add_line('No files found.')\n00620| return\n00621| end\n00622| if #lines > 1 then\n00623| output:add_line('Files:')\n00624| for i = 2, #lines do\n00625| local file = vim.trim(lines[i])\n00626| if file ~= '' then\n00627| output:add_line(' • ' .. file)\n00628| end\n00629| end\n00630| end\n00631| if metadata.truncated then\n00632| output:add_line(string.format('Results truncated, showing first %d files', metadata.count or '?'))\n00633| end\n00634| end\n00635| \n00636| ---@param output Output Output object to write to\n00637| ---@param part OpencodeMessagePart\n00638| function M._format_tool(output, part)\n00639| local tool = part.tool\n00640| if not tool or not part.state then\n00641| return\n00642| end\n00643| \n00644| local start_line = output:get_line_count() + 1\n00645| local input = part.state.input or {}\n00646| local metadata = part.state.metadata or {}\n00647| local tool_output = part.state.output or ''\n00648| \n00649| if state.current_permission and state.current_permission.messageID == part.messageID then\n00650| metadata = state.current_permission.metadata or metadata\n00651| end\n00652| \n00653| if tool == 'bash' then\n00654| M._format_bash_tool(output, input --[[@as BashToolInput]], metadata --[[@as BashToolMetadata]])\n00655| elseif tool == 'read' or tool == 'edit' or tool == 'write' then\n00656| M._format_file_tool(output, tool, input --[[@as FileToolInput]], metadata --[[@as FileToolMetadata]])\n00657| elseif tool == 'todowrite' then\n00658| M._format_todo_tool(output, part.state.title, input --[[@as TodoToolInput]])\n00659| elseif tool == 'glob' then\n00660| M._format_glob_tool(output, input --[[@as GlobToolInput]], metadata --[[@as GlobToolMetadata]])\n00661| elseif tool == 'list' then\n00662| M._format_list_tool(output, input --[[@as ListToolInput]], metadata --[[@as ListToolMetadata]], tool_output)\n00663| elseif tool == 'grep' then\n00664| M._format_grep_tool(output, input --[[@as GrepToolInput]], metadata --[[@as GrepToolMetadata]])\n00665| elseif tool == 'webfetch' then\n00666| M._format_webfetch_tool(output, input --[[@as WebFetchToolInput]])\n00667| elseif tool == 'task' then\n00668| M._format_task_tool(output, input --[[@as TaskToolInput]], metadata --[[@as TaskToolMetadata]], tool_output)\n00669| else\n00670| M._format_action(output, icons.get('tool') .. ' tool', tool)\n00671| end\n00672| \n00673| if part.state.status == 'error' and part.state.error then\n00674| output:add_line('')\n00675| M._format_callout(output, 'ERROR', part.state.error)\n00676| ---@diagnostic disable-next-line: undefined-field\n00677| elseif part.state.input and part.state.input.error then\n00678| output:add_line('')\n00679| ---I'm not sure about the type with state.input.error\n00680| ---@diagnostic disable-next-line: undefined-field\n00681| M._format_callout(output, 'ERROR', part.state.input.error)\n00682| end\n00683| \n00684| if\n00685| state.current_permission\n00686| and (\n00687| (\n00688| state.current_permission.tool\n00689| and state.current_permission.tool.callID == part.callID\n00690| and state.current_permission.tool.messageID == part.messageID\n00691| )\n00692| ---@TODO this is for backward compatibility, remove later\n00693| or (state.current_permission.messageID == part.messageID and state.current_permission.callID == part.callID)\n00694| )\n00695| then\n00696| M._handle_permission_request(output, part)\n00697| end\n00698| \n00699| local end_line = output:get_line_count()\n00700| if end_line - start_line > 1 then\n00701| M._add_vertical_border(output, start_line, end_line, 'OpencodeToolBorder', -1)\n00702| end\n00703| end\n00704| \n00705| ---@param output Output Output object to write to\n00706| ---@param input TaskToolInput data for the tool\n00707| ---@param metadata TaskToolMetadata Metadata for the tool use\n00708| ---@param tool_output string\n00709| function M._format_task_tool(output, input, metadata, tool_output)\n00710| local start_line = output:get_line_count() + 1\n00711| M._format_action(output, icons.get('task') .. ' task', input and input.description)\n00712| \n00713| if config.ui.output.tools.show_output then\n00714| if tool_output and tool_output ~= '' then\n00715| output:add_empty_line()\n00716| output:add_lines(vim.split(tool_output, '\\n'))\n00717| output:add_empty_line()\n00718| end\n00719| \n00720| if metadata.summary and type(metadata.summary) == 'table' then\n00721| for _, sub_part in ipairs(metadata.summary) do\n00722| if sub_part.type == 'tool' and sub_part.tool then\n00723| M._format_tool(output, sub_part)\n00724| end\n00725| end\n00726| end\n00727| end\n00728| \n00729| local end_line = output:get_line_count()\n00730| output:add_action({\n00731| text = '[S]elect Child Session',\n00732| type = 'select_child_session',\n00733| args = {},\n00734| key = 'S',\n00735| display_line = start_line - 1,\n00736| range = { from = start_line, to = end_line },\n00737| })\n00738| end\n00739| \n00740| ---@param output Output Output object to write to\n00741| ---@param lines string[]\n00742| ---@param language string\n00743| function M._format_code(output, lines, language)\n00744| output:add_empty_line()\n00745| --- NOTE: use longer code fence because lines could contain ```\n00746| output:add_line('`````' .. (language or ''))\n00747| output:add_lines(util.sanitize_lines(lines))\n00748| output:add_line('`````')\n00749| end\n00750| \n00751| ---@param output Output Output object to write to\n00752| ---@param code string\n00753| ---@param file_type string\n00754| function M._format_diff(output, code, file_type)\n00755| output:add_empty_line()\n00756| \n00757| --- NOTE: use longer code fence because code could contain ```\n00758| output:add_line('`````' .. file_type)\n00759| local lines = vim.split(code, '\\n')\n00760| if #lines > 5 then\n00761| lines = vim.list_slice(lines, 6)\n00762| end\n00763| \n00764| for _, line in ipairs(lines) do\n00765| local first_char = line:sub(1, 1)\n00766| if first_char == '+' or first_char == '-' then\n00767| local hl_group = first_char == '+' and 'OpencodeDiffAdd' or 'OpencodeDiffDelete'\n00768| output:add_line(' ' .. line:sub(2))\n00769| local line_idx = output:get_line_count()\n00770| output:add_extmark(line_idx - 1, function()\n00771| return {\n00772| end_col = 0,\n00773| end_row = line_idx,\n00774| virt_text = { { first_char, hl_group } },\n00775| hl_group = hl_group,\n00776| hl_eol = true,\n00777| priority = 5000,\n00778| right_gravity = true,\n00779| end_right_gravity = false,\n00780| virt_text_hide = false,\n00781| virt_text_pos = 'overlay',\n00782| virt_text_repeat_linebreak = false,\n00783| }\n00784| end)\n00785| else\n00786| output:add_line(line)\n00787| end\n00788| end\n00789| output:add_line('`````')\n00790| end\n00791| \n00792| ---@param output Output Output object to write to\n00793| ---@param start_line number\n00794| ---@param end_line number\n00795| ---@param hl_group string Highlight group for the border character\n00796| ---@param win_col number\n00797| ---@param text_hl_group? string Optional highlight group for the background/foreground of text lines\n00798| function M._add_vertical_border(output, start_line, end_line, hl_group, win_col, text_hl_group)\n00799| for line = start_line, end_line do\n00800| local extmark_opts = {\n00801| virt_text = { { require('opencode.ui.icons').get('border'), hl_group } },\n00802| virt_text_pos = 'overlay',\n00803| virt_text_win_col = win_col,\n00804| virt_text_repeat_linebreak = true,\n00805| }\n00806| \n00807| -- Add line highlight if text_hl_group is provided\n00808| if text_hl_group then\n00809| extmark_opts.line_hl_group = text_hl_group\n00810| end\n00811| \n00812| output:add_extmark(line - 1, extmark_opts --[[@as OutputExtmark]])\n00813| end\n00814| end\n00815| \n00816| ---Formats a single message part and returns the resulting output object\n00817| ---@param part OpencodeMessagePart The part to format\n00818| ---@param message? OpencodeMessage Optional message object to extract role and mentions from\n00819| ---@param is_last_part? boolean Whether this is the last part in the message, used to show an error if there is one\n00820| ---@return Output\n00821| function M.format_part(part, message, is_last_part)\n00822| local output = Output.new()\n00823| \n00824| if not message or not message.info or not message.info.role then\n00825| return output\n00826| end\n00827| \n00828| local content_added = false\n00829| local role = message.info.role\n00830| \n00831| if role == 'user' then\n00832| if part.type == 'text' and part.text then\n00833| if part.synthetic == true then\n00834| M._format_selection_context(output, part)\n00835| M._format_cursor_data_context(output, part)\n00836| M._format_diagnostics_context(output, part)\n00837| else\n00838| M._format_user_prompt(output, vim.trim(part.text), message)\n00839| content_added = true\n00840| end\n00841| elseif part.type == 'file' then\n00842| local file_line = M._format_context_file(output, part.filename)\n00843| if file_line then\n00844| M._add_vertical_border(output, file_line - 1, file_line, 'OpencodeMessageRoleUser', -3)\n00845| content_added = true\n00846| end\n00847| end\n00848| elseif role == 'assistant' then\n00849| if part.type == 'text' and part.text then\n00850| M._format_assistant_message(output, vim.trim(part.text))\n00851| content_added = true\n00852| elseif part.type == 'reasoning' and part.text then\n00853| M._format_reasoning(output, part)\n00854| content_added = true\n00855| elseif part.type == 'tool' then\n00856| M._format_tool(output, part)\n00857| content_added = true\n00858| elseif part.type == 'patch' and part.hash then\n00859| M._format_patch(output, part)\n00860| content_added = true\n00861| end\n00862| end\n00863| \n00864| if content_added then\n00865| output:add_empty_line()\n00866| end\n00867| \n00868| if is_last_part and role == 'assistant' and message.info.error and message.info.error ~= '' then\n00869| local error = message.info.error\n00870| local error_message = error.data and error.data.message or vim.inspect(error)\n00871| M._format_callout(output, 'ERROR', error_message)\n00872| output:add_empty_line()\n00873| end\n00874| \n00875| return output\n00876| end\n00877| \n00878| return M\n00879| \n\n(End of file - total 879 lines)\n",
+ "synthetic": true
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "file",
+ "url": "file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua",
+ "id": "prt_b8e7c60a7002ybV09VDHoQQeO7",
+ "filename": "lua/opencode/ui/formatter.lua",
+ "messageID": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "mime": "text/plain"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "text",
+ "id": "prt_b8e7c60a3002XHHlk77vAPApvR",
+ "messageID": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "text": "{\"content\":[{\"msg\":\"expected `SessionRevertInfo` but found `SessionRevertInfo?`.\",\"severity\":2,\"pos\":\"l156:c68\"},{\"msg\":\"expected `integer?` but found `number`.\",\"severity\":2,\"pos\":\"l490:c43\"},{\"msg\":\"expected `integer` but found `number`.\",\"severity\":2,\"pos\":\"l492:c45\"},{\"msg\":\"expected `integer?` but found `number`.\",\"severity\":2,\"pos\":\"l492:c62\"},{\"msg\":\"state.active_session may be nil\",\"severity\":2,\"pos\":\"l156:c68\"},{\"msg\":\"state.messages[#state.messages] may be nil\",\"severity\":2,\"pos\":\"l272:c74\"},{\"msg\":\"state.messages may be nil\",\"severity\":2,\"pos\":\"l272:c74\"},{\"msg\":\"Undefined field `[diag.severity]`.\",\"severity\":2,\"pos\":\"l435:c42\"},{\"msg\":\"Undefined field `command`.\",\"severity\":2,\"pos\":\"l526:c34\"},{\"msg\":\"Undefined field `command`.\",\"severity\":2,\"pos\":\"l527:c47\"},{\"msg\":\"Cannot assign `number` to `integer`.\",\"severity\":2,\"pos\":\"l493:c5\"}],\"context_type\":\"diagnostics\"}",
+ "synthetic": true
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "title": "New session - 2026-01-05T14:07:52.149Z",
+ "version": "1.1.2",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "time": { "updated": 1767622074603, "created": 1767622072149 }
+ }
+ },
+ "type": "session.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "info": {
+ "providerID": "github-copilot",
+ "role": "assistant",
+ "path": {
+ "root": "/home/francis/Projects/_nvim/opencode.nvim",
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "agent": "build",
+ "time": { "created": 1767622074609 },
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "mode": "build",
+ "modelID": "gpt-4.1",
+ "id": "msg_b8e7c60f1001aEWYlAaDRXQ4aJ",
+ "parentID": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "cost": 0,
+ "tokens": { "output": 0, "reasoning": 0, "input": 0, "cache": { "write": 0, "read": 0 } }
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "time": { "created": 1767622074530 },
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "role": "user",
+ "id": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "agent": "build",
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "summary": { "diffs": [] }
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "title": "New session - 2026-01-05T14:07:52.149Z",
+ "version": "1.1.2",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "time": { "updated": 1767622074670, "created": 1767622072149 },
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "summary": { "deletions": 0, "additions": 0, "files": 0 }
+ }
+ },
+ "type": "session.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "step-start",
+ "id": "prt_b8e7c6672001F10WAiQKbzNEtE",
+ "snapshot": "5ba6e95774829e7f501299039b72b72dc32c6620",
+ "messageID": "msg_b8e7c60f1001aEWYlAaDRXQ4aJ"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "tool",
+ "messageID": "msg_b8e7c60f1001aEWYlAaDRXQ4aJ",
+ "id": "prt_b8e7c6686001cCV44vsFtbpF42",
+ "state": { "status": "pending", "input": {}, "raw": "" },
+ "callID": "call_KAC0LdAxKEbU6HTAPH5QJfGx",
+ "tool": "bash"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "type": "tool",
+ "messageID": "msg_b8e7c60f1001aEWYlAaDRXQ4aJ",
+ "id": "prt_b8e7c6686001cCV44vsFtbpF42",
+ "state": {
+ "status": "running",
+ "input": { "description": "Shows working tree status", "command": "git status" },
+ "time": { "start": 1767622076189 }
+ },
+ "callID": "call_KAC0LdAxKEbU6HTAPH5QJfGx",
+ "tool": "bash"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "tool": { "messageID": "msg_b8e7c60f1001aEWYlAaDRXQ4aJ", "callID": "call_KAC0LdAxKEbU6HTAPH5QJfGx" },
+ "patterns": ["git status"],
+ "id": "per_b8e7c6744001DX6EZ9KHM15RLi",
+ "permission": "bash",
+ "always": ["git status*"],
+ "metadata": {}
+ },
+ "type": "permission.asked"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "time": { "created": 1767622074530 },
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "role": "user",
+ "id": "msg_b8e7c60a2001Kisjwk2mVB4dye",
+ "agent": "build",
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "summary": { "title": "Running git status to list changed files", "diffs": [] }
+ }
+ },
+ "type": "message.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" },
+ {
+ "properties": {
+ "info": {
+ "title": "Running git status for formatter.lua changes",
+ "version": "1.1.2",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_47183a8abffeZzOLeJ3j2KV8f8",
+ "time": { "updated": 1767622082619, "created": 1767622072149 },
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "summary": { "deletions": 0, "additions": 0, "files": 0 }
+ }
+ },
+ "type": "session.updated"
+ },
+ { "properties": [], "type": "custom.emit_events.finished" }
+]
diff --git a/tests/data/permission-prompt.expected.json b/tests/data/permission-prompt.expected.json
index c4a91d6b..88b0001f 100644
--- a/tests/data/permission-prompt.expected.json
+++ b/tests/data/permission-prompt.expected.json
@@ -1 +1,453 @@
-{"lines":["----","","","Perfect! Now I understand how it works. The message headers have extmarks with `virt_text` where the first element contains the icon (either `header_user` or `header_assistant`). Let me check the output_window module to understand the extmark namespace:","","** run** `Find extmark namespace usage`","","`````bash","> rg \"nvim_buf_get_extmarks|ns_id\" /Users/cam/Dev/neovim-dev/opencode.nvim/lua/opencode/ui/output_window.lua -B 2 -A 2","","`````","","----","",""," Permission Required",""," *bash* `rg \"nvim_buf_get_extmarks|ns_id\" /Users/cam/Dev/neovim-dev/opencode.nvim/lua/opencode/ui/output_window.lua -B 2 -A 2`",""," 1. Allow once "," 2. Reject"," 3. Allow always","","Navigate: `j`/`k` or `↑`/`↓` Select: `` or `1-3`","",""],"extmarks":[[1,1,0,{"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["PLAN","OpencodeMessageRoleAssistant"],[" claude-sonnet-4.5","OpencodeHint"],[" (2025-10-16 04:27:36)","OpencodeHint"],[" [msg_9eb45fbe60020xE560OGH3Vdoo]","OpencodeHint"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":10,"virt_text_repeat_linebreak":false,"virt_text_win_col":-3}],[2,5,0,{"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_win_col":-1}],[3,6,0,{"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_win_col":-1}],[4,7,0,{"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_win_col":-1}],[5,8,0,{"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_win_col":-1}],[6,9,0,{"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_win_col":-1}],[7,10,0,{"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_win_col":-1}],[8,13,0,{"virt_text":[[" ","OpencodeMessageRoleSystem"],[" "],["SYSTEM","OpencodeMessageRoleSystem"],["","OpencodeHint"],["","OpencodeHint"],[" [permission-display-message]","OpencodeHint"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":10,"virt_text_repeat_linebreak":false,"virt_text_win_col":-3}],[9,15,0,{"priority":4096,"line_hl_group":"OpencodePermissionTitle","ns_id":3,"right_gravity":true}],[10,15,0,{"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_win_col":-2}],[11,16,0,{"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_win_col":-2}],[12,17,0,{"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_win_col":-2}],[13,18,0,{"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_win_col":-2}],[14,19,0,{"priority":4096,"line_hl_group":"OpencodeDialogOptionHover","ns_id":3,"right_gravity":true}],[15,19,0,{"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_win_col":-2}],[16,19,2,{"virt_text":[["› ","OpencodeDialogOptionHover"]],"virt_text_pos":"overlay","ns_id":3,"right_gravity":true,"virt_text_hide":false,"virt_text_repeat_linebreak":false,"priority":4096}],[17,20,0,{"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_win_col":-2}],[18,21,0,{"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_win_col":-2}],[19,22,0,{"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_win_col":-2}],[20,23,0,{"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","ns_id":3,"right_gravity":true,"virt_text_hide":false,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_win_col":-2}]],"timestamp":1769449859,"actions":[]}
\ No newline at end of file
+{
+ "actions": [],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "PLAN",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " claude-sonnet-4.5",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-16 04:27:36)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9eb45fbe60020xE560OGH3Vdoo]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 5,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 3,
+ 6,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 4,
+ 7,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 5,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 6,
+ 9,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 7,
+ 10,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 8,
+ 13,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleSystem"
+ ],
+ [
+ " "
+ ],
+ [
+ "SYSTEM",
+ "OpencodeMessageRoleSystem"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " [permission-display-message]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 9,
+ 15,
+ 0,
+ {
+ "line_hl_group": "OpencodePermissionTitle",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true
+ }
+ ],
+ [
+ 10,
+ 15,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 11,
+ 16,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 12,
+ 17,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 13,
+ 18,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 14,
+ 19,
+ 0,
+ {
+ "line_hl_group": "OpencodeDialogOptionHover",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true
+ }
+ ],
+ [
+ 15,
+ 19,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 16,
+ 19,
+ 2,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "› ",
+ "OpencodeDialogOptionHover"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "overlay",
+ "virt_text_repeat_linebreak": false
+ }
+ ],
+ [
+ 17,
+ 20,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 18,
+ 21,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 19,
+ 22,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 20,
+ 23,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "Perfect! Now I understand how it works. The message headers have extmarks with `virt_text` where the first element contains the icon (either `header_user` or `header_assistant`). Let me check the output_window module to understand the extmark namespace:",
+ "",
+ "** run** `Find extmark namespace usage`",
+ "",
+ "`````bash",
+ "> rg \"nvim_buf_get_extmarks|ns_id\" /Users/cam/Dev/neovim-dev/opencode.nvim/lua/opencode/ui/output_window.lua -B 2 -A 2",
+ "",
+ "`````",
+ "",
+ "----",
+ "",
+ "",
+ " Permission Required",
+ "",
+ " *bash* `rg \"nvim_buf_get_extmarks|ns_id\" /Users/cam/Dev/neovim-dev/opencode.nvim/lua/opencode/ui/output_window.lua -B 2 -A 2`",
+ "",
+ " 1. Allow once ",
+ " 2. Reject",
+ " 3. Allow always",
+ "",
+ "Navigate: `j`/`k` or `↑`/`↓` Select: `` or `1-3`",
+ "",
+ ""
+ ],
+ "timestamp": 1770748578
+}
\ No newline at end of file
diff --git a/tests/data/permission.expected.json b/tests/data/permission.expected.json
index 176d38fd..1e8833ed 100644
--- a/tests/data/permission.expected.json
+++ b/tests/data/permission.expected.json
@@ -1 +1,325 @@
-{"extmarks":[[1,1,0,{"ns_id":3,"priority":10,"virt_text_hide":false,"right_gravity":true,"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-12 05:43:49)","OpencodeHint"],[" [msg_9d6f253910015UFmkGkiWtUsRW]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"virt_text_repeat_linebreak":false}],[2,2,0,{"ns_id":3,"priority":4096,"virt_text_hide":false,"right_gravity":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"virt_text_repeat_linebreak":true}],[3,3,0,{"ns_id":3,"priority":4096,"virt_text_hide":false,"right_gravity":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"virt_text_repeat_linebreak":true}],[4,6,0,{"ns_id":3,"priority":10,"virt_text_hide":false,"right_gravity":true,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" claude-sonnet-4.5","OpencodeHint"],[" (2025-10-12 05:43:49)","OpencodeHint"],[" [msg_9d6f253df001TjqxW12FAjGf5s]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"virt_text_repeat_linebreak":false}],[5,8,0,{"ns_id":3,"priority":4096,"virt_text_hide":false,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[6,9,0,{"ns_id":3,"priority":4096,"virt_text_hide":false,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[7,10,0,{"ns_id":3,"priority":4096,"virt_text_hide":false,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[8,11,0,{"ns_id":3,"priority":4096,"virt_text_hide":false,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[9,12,0,{"ns_id":3,"priority":4096,"virt_text_hide":false,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"virt_text_repeat_linebreak":true}],[10,17,0,{"ns_id":3,"priority":10,"virt_text_hide":false,"right_gravity":true,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" claude-sonnet-4.5","OpencodeHint"],[" (2025-10-12 05:44:00)","OpencodeHint"],[" [msg_9d6f27f4800103Tp3N6i6JW53p]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"virt_text_repeat_linebreak":false}]],"actions":[{"key":"R","type":"diff_revert_selected_file","text":"[R]evert file","args":["c78fb2dd2d533cfe530692cc3e3c8f92a0e4af1d"],"range":{"from":14,"to":14},"display_line":14},{"key":"A","type":"diff_revert_all","text":"Revert [A]ll","args":["c78fb2dd2d533cfe530692cc3e3c8f92a0e4af1d"],"range":{"from":14,"to":14},"display_line":14},{"key":"D","type":"diff_open","text":"[D]iff","args":["c78fb2dd2d533cfe530692cc3e3c8f92a0e4af1d"],"range":{"from":14,"to":14},"display_line":14}],"lines":["----","","","add a file, test.txt, with \":)\" in it","","----","","","** write** `/Users/cam/tmp/a/test.txt`","","`````txt",":)","`````","","** Created Snapshot** `c78fb2dd`","","----","","",""],"timestamp":1769172178}
\ No newline at end of file
+{
+ "actions": [
+ {
+ "args": [
+ "c78fb2dd2d533cfe530692cc3e3c8f92a0e4af1d"
+ ],
+ "display_line": 14,
+ "key": "R",
+ "range": {
+ "from": 14,
+ "to": 14
+ },
+ "text": "[R]evert file",
+ "type": "diff_revert_selected_file"
+ },
+ {
+ "args": [
+ "c78fb2dd2d533cfe530692cc3e3c8f92a0e4af1d"
+ ],
+ "display_line": 14,
+ "key": "A",
+ "range": {
+ "from": 14,
+ "to": 14
+ },
+ "text": "Revert [A]ll",
+ "type": "diff_revert_all"
+ },
+ {
+ "args": [
+ "c78fb2dd2d533cfe530692cc3e3c8f92a0e4af1d"
+ ],
+ "display_line": 14,
+ "key": "D",
+ "range": {
+ "from": 14,
+ "to": 14
+ },
+ "text": "[D]iff",
+ "type": "diff_open"
+ }
+ ],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-12 05:43:49)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9d6f253910015UFmkGkiWtUsRW]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 2,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 3,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 4,
+ 6,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " claude-sonnet-4.5",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-12 05:43:49)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9d6f253df001TjqxW12FAjGf5s]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 5,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 6,
+ 9,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 7,
+ 10,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 8,
+ 11,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 9,
+ 12,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 10,
+ 17,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " claude-sonnet-4.5",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-12 05:44:00)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9d6f27f4800103Tp3N6i6JW53p]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "add a file, test.txt, with \":)\" in it",
+ "",
+ "----",
+ "",
+ "",
+ "** write** `/Users/cam/tmp/a/test.txt`",
+ "",
+ "`````txt",
+ ":)",
+ "`````",
+ "",
+ "** Created Snapshot** `c78fb2dd`",
+ "",
+ "----",
+ "",
+ "",
+ ""
+ ],
+ "timestamp": 1770748578
+}
\ No newline at end of file
diff --git a/tests/data/permission_error.json b/tests/data/permission_error.json
index 541ec3ca..9286166b 100644
--- a/tests/data/permission_error.json
+++ b/tests/data/permission_error.json
@@ -1 +1,1677 @@
-[{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"role":"user","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","agent":"plan","id":"msg_b94b69474001IGYFIs72LkX50a","time":{"created":1767726552181},"model":{"providerID":"anthropic","modelID":"claude-sonnet-4-5"}}}},{"type":"message.part.updated","properties":{"part":{"type":"agent","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","messageID":"msg_b94b69474001IGYFIs72LkX50a","id":"prt_b94b69475001ahJ6Yfg4gUhw5v","source":{"end":5,"value":"@nvim","start":0},"name":"nvim"}}},{"type":"message.part.updated","properties":{"part":{"type":"text","text":"Use the above message and context to generate a prompt and call the task tool with subagent: nvim","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","synthetic":true,"id":"prt_b94b69475002LiAJbv6BRaVSpQ","messageID":"msg_b94b69474001IGYFIs72LkX50a"}}},{"type":"message.part.updated","properties":{"part":{"type":"text","text":"Called the Read tool with the following input: {\"filePath\":\"/Users/matigreen/dotfiles/nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua\"}","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","synthetic":true,"id":"prt_b94b69475004x7HkswYBcQhl62","messageID":"msg_b94b69474001IGYFIs72LkX50a"}}},{"type":"message.part.updated","properties":{"part":{"type":"text","text":"\n00001| return {\n00002| \"sudo-tee/opencode.nvim\",\n00003| config = function()\n00004| -- Check if custom configs are enabled\n00005| local custom_enabled = vim.g.opencode_custom_enabled == true\n00006| \n00007| if custom_enabled then\n00008| -- =========================================================================\n00009| -- CUSTOM CONFIGURATION MODE\n00010| -- =========================================================================\n00011| require(\"opencode\").setup({\n00012| default_mode = \"plan\", -- Default to Plan mode instead of Build\n00013| keymap = {\n00014| editor = {\n00015| [\"o\"] = { \"switch_mode\", desc = \"Toggle agent (Plan/Build)\" },\n00016| [\"ou\"] = { \"undo\", desc = \"Undo last message\" },\n00017| [\"o\"] = { \"redo\", desc = \"Redo message\" },\n00018| -- Override default provider switcher with custom favorites\n00019| [\"op\"] = {\n00020| function()\n00021| require(\"gmati.plugins.ai.opencode_favorites\").select_favorite_provider()\n00022| end,\n00023| desc = \"Switch provider (favorites)\",\n00024| },\n00025| },\n00026| input_window = {\n00027| -- Enter submits only in normal mode\n00028| [\"\"] = { \"submit_input_prompt\", mode = \"n\" },\n00029| },\n00030| },\n00031| ui = {\n00032| -- Disable built-in status displays (we use lualine instead)\n00033| display_model = false,\n00034| display_context_size = false,\n00035| display_cost = false,\n00036| },\n00037| debug = {\n00038| capture_streamed_events = true\n00039| }\n00040| })\n00041| \n00042| -- Apply UI patches to customize OpenCode rendering\n00043| vim.defer_fn(function()\n00044| require(\"gmati.plugins.ai.opencode_ui_patches\").apply_all()\n00045| end, 0)\n00046| \n00047| -- Setup custom keymaps (mode switching, diagnostics, emergency)\n00048| require(\"gmati.plugins.ai.opencode_keymaps\").setup()\n00049| \n00050| -- Setup diagnostics monitoring (health checks, error tracking)\n00051| vim.defer_fn(function()\n00052| local ok, diagnostics = pcall(require, \"gmati.plugins.ai.opencode_diagnostics\")\n00053| if ok then\n00054| diagnostics.setup()\n00055| end\n00056| end, 300)\n00057| \n00058| -- Setup LSP/features integration (disable during thinking)\n00059| vim.defer_fn(function()\n00060| local ok, integration = pcall(require, \"gmati.plugins.ai.opencode_integration\")\n00061| if ok then\n00062| integration.setup()\n00063| end\n00064| end, 200)\n00065| \n00066| -- Cleanup on exit\n00067| vim.api.nvim_create_autocmd(\"VimLeavePre\", {\n00068| callback = function()\n00069| local ok, integration = pcall(require, \"gmati.plugins.ai.opencode_integration\")\n00070| if ok then\n00071| integration.cleanup()\n00072| end\n00073| \n00074| local ok_diag, diagnostics = pcall(require, \"gmati.plugins.ai.opencode_diagnostics\")\n00075| if ok_diag then\n00076| diagnostics.cleanup()\n00077| end\n00078| end,\n00079| })\n00080| else\n00081| -- =========================================================================\n00082| -- VANILLA CONFIGURATION MODE\n00083| -- =========================================================================\n00084| require(\"opencode\").setup({\n00085| default_mode = \"plan\", -- Keep your default mode preference\n00086| debug = {\n00087| capture_streamed_events = true\n00088| }\n00089| })\n00090| end\n00091| end,\n00092| dependencies = {\n00093| \"nvim-lua/plenary.nvim\",\n00094| {\n00095| \"MeanderingProgrammer/render-markdown.nvim\",\n00096| opts = {\n00097| anti_conceal = { enabled = false },\n00098| file_types = { \"markdown\", \"opencode_output\" },\n00099| },\n00100| ft = { \"markdown\", \"Avante\", \"copilot-chat\", \"opencode_output\" },\n00101| },\n00102| -- Optional, for file mentions and commands completion\n00103| \"hrsh7th/nvim-cmp\",\n00104| -- Optional, for file mentions picker\n00105| \"folke/snacks.nvim\",\n00106| },\n00107| }\n00108| \n\n(End of file - total 108 lines)\n","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","synthetic":true,"id":"prt_b94b69478001tl1GxEgWIuCfyD","messageID":"msg_b94b69474001IGYFIs72LkX50a"}}},{"type":"message.part.updated","properties":{"part":{"type":"file","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","url":"file:///Users/matigreen/dotfiles/nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua","filename":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua","id":"prt_b94b694780020D1il48agKCnJG","messageID":"msg_b94b69474001IGYFIs72LkX50a","mime":"text/plain"}}},{"type":"message.part.updated","properties":{"part":{"type":"text","text":"@nvim my alt-M keybind does not work for opencode.nvim plugin for nvim, but it is the default keymap of the plugin\n","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","id":"prt_b94b694750033Bhav31Nb5Zl3j","messageID":"msg_b94b69474001IGYFIs72LkX50a"}}},{"type":"session.updated","properties":{"info":{"title":"New session - 2026-01-06T19:08:58.999Z","version":"1.0.220","directory":"/Users/matigreen/dotfiles","id":"ses_46b499f08ffe3aldWmWZoH6N2m","time":{"created":1767726538999,"updated":1767726552190},"projectID":"b8136e83cf077521b7177c9660d223a1759f881e"}}},{"type":"message.updated","properties":{"info":{"role":"assistant","tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"parentID":"msg_b94b69474001IGYFIs72LkX50a","providerID":"anthropic","time":{"created":1767726552205},"id":"msg_b94b6948d002pFurK7t7q4bSyb","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","modelID":"claude-sonnet-4-5","mode":"plan","cost":0,"agent":"plan","path":{"cwd":"/Users/matigreen/dotfiles","root":"/Users/matigreen/dotfiles"}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"session.updated","properties":{"info":{"title":"Debugging Alt-M keybind in opencode.nvim","version":"1.0.220","directory":"/Users/matigreen/dotfiles","id":"ses_46b499f08ffe3aldWmWZoH6N2m","time":{"created":1767726538999,"updated":1767726553777},"projectID":"b8136e83cf077521b7177c9660d223a1759f881e"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"role":"user","summary":{"diffs":[]},"sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","time":{"created":1767726552181},"id":"msg_b94b69474001IGYFIs72LkX50a","agent":"plan","model":{"providerID":"anthropic","modelID":"claude-sonnet-4-5"}}}},{"type":"session.updated","properties":{"info":{"title":"Debugging Alt-M keybind in opencode.nvim","version":"1.0.220","projectID":"b8136e83cf077521b7177c9660d223a1759f881e","directory":"/Users/matigreen/dotfiles","id":"ses_46b499f08ffe3aldWmWZoH6N2m","summary":{"deletions":0,"files":0,"additions":0},"time":{"created":1767726538999,"updated":1767726554586}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"role":"user","summary":{"title":"Debugging alt-M keybind in opencode.nvim","diffs":[]},"sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","system":"# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n","time":{"created":1767726552181},"id":"msg_b94b69474001IGYFIs72LkX50a","agent":"plan","model":{"providerID":"anthropic","modelID":"claude-sonnet-4-5"}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"step-start","snapshot":"29b76c5b84a59e892d23447cd82abb3afea86e41","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","id":"prt_b94b6b0ad0015WllkaFXZte33S","messageID":"msg_b94b6948d002pFurK7t7q4bSyb"}}},{"type":"message.part.updated","properties":{"delta":"I'll","part":{"type":"text","text":"I'll","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","id":"prt_b94b6b0af001kAm5cXAFC8lXrL","time":{"start":1767726559407},"messageID":"msg_b94b6948d002pFurK7t7q4bSyb"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":" the","part":{"type":"text","text":"I'll help you investigate why the","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","id":"prt_b94b6b0af001kAm5cXAFC8lXrL","time":{"start":1767726559407},"messageID":"msg_b94b6948d002pFurK7t7q4bSyb"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":"-","part":{"type":"text","text":"I'll help you investigate why the `alt-","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","id":"prt_b94b6b0af001kAm5cXAFC8lXrL","time":{"start":1767726559407},"messageID":"msg_b94b6948d002pFurK7t7q4bSyb"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":"M","part":{"type":"text","text":"I'll help you investigate why the `alt-M","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","id":"prt_b94b6b0af001kAm5cXAFC8lXrL","time":{"start":1767726559407},"messageID":"msg_b94b6948d002pFurK7t7q4bSyb"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":"` ke","part":{"type":"text","text":"I'll help you investigate why the `alt-M` ke","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","id":"prt_b94b6b0af001kAm5cXAFC8lXrL","time":{"start":1767726559407},"messageID":"msg_b94b6948d002pFurK7t7q4bSyb"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":"ybin","part":{"type":"text","text":"I'll help you investigate why the `alt-M` keybin","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","id":"prt_b94b6b0af001kAm5cXAFC8lXrL","time":{"start":1767726559407},"messageID":"msg_b94b6948d002pFurK7t7q4bSyb"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":" open","part":{"type":"text","text":"I'll help you investigate why the `alt-M` keybind isn't working for the open","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","id":"prt_b94b6b0af001kAm5cXAFC8lXrL","time":{"start":1767726559407},"messageID":"msg_b94b6948d002pFurK7t7q4bSyb"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":"code.","part":{"type":"text","text":"I'll help you investigate why the `alt-M` keybind isn't working for the opencode.","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","id":"prt_b94b6b0af001kAm5cXAFC8lXrL","time":{"start":1767726559407},"messageID":"msg_b94b6948d002pFurK7t7q4bSyb"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":" agent","part":{"type":"text","text":"I'll help you investigate why the `alt-M` keybind isn't working for the opencode.nvim plugin. Let me delegate this to the nvim specialist agent","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","id":"prt_b94b6b0af001kAm5cXAFC8lXrL","time":{"start":1767726559407},"messageID":"msg_b94b6948d002pFurK7t7q4bSyb"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":".","part":{"type":"text","text":"I'll help you investigate why the `alt-M` keybind isn't working for the opencode.nvim plugin. Let me delegate this to the nvim specialist agent.","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","id":"prt_b94b6b0af001kAm5cXAFC8lXrL","time":{"start":1767726559407},"messageID":"msg_b94b6948d002pFurK7t7q4bSyb"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","text":"I'll help you investigate why the `alt-M` keybind isn't working for the opencode.nvim plugin. Let me delegate this to the nvim specialist agent.","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","id":"prt_b94b6b0af001kAm5cXAFC8lXrL","time":{"start":1767726560755,"end":1767726560755},"messageID":"msg_b94b6948d002pFurK7t7q4bSyb"}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","callID":"toolu_017Li9bzxEHcp7pwBxRu4MxU","tool":"task","id":"prt_b94b6b5f3001JaaXlpjO9TFn2O","messageID":"msg_b94b6948d002pFurK7t7q4bSyb","state":{"input":{},"raw":"","status":"pending"}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"session.updated","properties":{"info":{"title":"Debug alt-M keybind issue (@nvim subagent)","version":"1.0.220","projectID":"b8136e83cf077521b7177c9660d223a1759f881e","directory":"/Users/matigreen/dotfiles","parentID":"ses_46b499f08ffe3aldWmWZoH6N2m","time":{"created":1767726567748,"updated":1767726567748},"id":"ses_46b492ebbffel5oIJ1qUl9GKFh"}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","callID":"toolu_017Li9bzxEHcp7pwBxRu4MxU","tool":"task","id":"prt_b94b6b5f3001JaaXlpjO9TFn2O","messageID":"msg_b94b6948d002pFurK7t7q4bSyb","state":{"title":"Debug alt-M keybind issue","metadata":{"sessionId":"ses_46b492ebbffel5oIJ1qUl9GKFh"},"input":{"subagent_type":"nvim","prompt":"The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.","description":"Debug alt-M keybind issue"},"time":{"start":1767726567751},"status":"running"}}}},{"type":"message.updated","properties":{"info":{"role":"user","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","tools":{"todoread":false,"task":false,"browser_*":false,"atlassian_*":false,"jira_get":true,"confluence_*":false,"todowrite":false,"playwright":false,"write":true,"edit":true,"bash":true},"agent":"nvim","id":"msg_b94b6d147001k2DbeF1m2JpIP3","time":{"created":1767726567752},"model":{"providerID":"anthropic","modelID":"claude-sonnet-4-5"}}}},{"type":"message.part.updated","properties":{"part":{"type":"text","text":"The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","id":"prt_b94b6d148001ScODvsxRwAPkK7","messageID":"msg_b94b6d147001k2DbeF1m2JpIP3"}}},{"type":"session.updated","properties":{"info":{"title":"Debug alt-M keybind issue (@nvim subagent)","version":"1.0.220","projectID":"b8136e83cf077521b7177c9660d223a1759f881e","directory":"/Users/matigreen/dotfiles","parentID":"ses_46b499f08ffe3aldWmWZoH6N2m","time":{"created":1767726567748,"updated":1767726567754},"id":"ses_46b492ebbffel5oIJ1qUl9GKFh"}}},{"type":"message.updated","properties":{"info":{"role":"assistant","tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"parentID":"msg_b94b6d147001k2DbeF1m2JpIP3","providerID":"anthropic","time":{"created":1767726567755},"id":"msg_b94b6d14b001y9ggcfX7Qmvfb4","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","modelID":"claude-sonnet-4-5","mode":"nvim","cost":0,"agent":"nvim","path":{"cwd":"/Users/matigreen/dotfiles","root":"/Users/matigreen/dotfiles"}}}},{"type":"message.updated","properties":{"info":{"role":"user","summary":{"diffs":[]},"sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","tools":{"todoread":false,"task":false,"browser_*":false,"atlassian_*":false,"jira_get":true,"confluence_*":false,"todowrite":false,"playwright":false,"write":true,"edit":true,"bash":true},"time":{"created":1767726567752},"id":"msg_b94b6d147001k2DbeF1m2JpIP3","agent":"nvim","model":{"providerID":"anthropic","modelID":"claude-sonnet-4-5"}}}},{"type":"session.updated","properties":{"info":{"projectID":"b8136e83cf077521b7177c9660d223a1759f881e","title":"Debug alt-M keybind issue (@nvim subagent)","version":"1.0.220","time":{"created":1767726567748,"updated":1767726567766},"directory":"/Users/matigreen/dotfiles","parentID":"ses_46b499f08ffe3aldWmWZoH6N2m","summary":{"deletions":0,"files":0,"additions":0},"id":"ses_46b492ebbffel5oIJ1qUl9GKFh"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"role":"user","summary":{"title":"Debugging alt-M keybind opencode.nvim","diffs":[]},"sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","tools":{"todoread":false,"task":false,"browser_*":false,"atlassian_*":false,"jira_get":true,"confluence_*":false,"todowrite":false,"playwright":false,"write":true,"edit":true,"bash":true},"time":{"created":1767726567752},"id":"msg_b94b6d147001k2DbeF1m2JpIP3","agent":"nvim","model":{"providerID":"anthropic","modelID":"claude-sonnet-4-5"}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"step-start","snapshot":"29b76c5b84a59e892d23447cd82abb3afea86e41","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","id":"prt_b94b6de23001y1RTIdtsaHvsAw","messageID":"msg_b94b6d14b001y9ggcfX7Qmvfb4"}}},{"type":"message.part.updated","properties":{"delta":" the `","part":{"type":"text","text":"I'll investigate the `","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","id":"prt_b94b6de240010A9XWmezoH5cz9","time":{"start":1767726571044},"messageID":"msg_b94b6d14b001y9ggcfX7Qmvfb4"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":"code.nvim.","part":{"type":"text","text":"I'll investigate the `alt-M` keybind issue for opencode.nvim.","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","id":"prt_b94b6de240010A9XWmezoH5cz9","time":{"start":1767726571044},"messageID":"msg_b94b6d14b001y9ggcfX7Qmvfb4"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":" files","part":{"type":"text","text":"I'll investigate the `alt-M` keybind issue for opencode.nvim. Let me start by examining the relevant configuration files","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","id":"prt_b94b6de240010A9XWmezoH5cz9","time":{"start":1767726571044},"messageID":"msg_b94b6d14b001y9ggcfX7Qmvfb4"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","text":"I'll investigate the `alt-M` keybind issue for opencode.nvim. Let me start by examining the relevant configuration files.","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","id":"prt_b94b6de240010A9XWmezoH5cz9","time":{"start":1767726571695,"end":1767726571695},"messageID":"msg_b94b6d14b001y9ggcfX7Qmvfb4"}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","callID":"toolu_01BbJ53KgPXPLXqVbMQhaPyT","tool":"read","id":"prt_b94b6e0b3001mCVItg2EJfPAB2","messageID":"msg_b94b6d14b001y9ggcfX7Qmvfb4","state":{"input":{},"raw":"","status":"pending"}}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","callID":"toolu_017Li9bzxEHcp7pwBxRu4MxU","tool":"task","id":"prt_b94b6b5f3001JaaXlpjO9TFn2O","messageID":"msg_b94b6948d002pFurK7t7q4bSyb","state":{"title":"Debug alt-M keybind issue","metadata":{"summary":[{"tool":"read","id":"prt_b94b6e0b3001mCVItg2EJfPAB2","state":{"status":"pending"}}],"sessionId":"ses_46b492ebbffel5oIJ1qUl9GKFh"},"input":{"subagent_type":"nvim","prompt":"The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.","description":"Debug alt-M keybind issue"},"time":{"start":1767726571700},"status":"running"}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","callID":"toolu_01BbJ53KgPXPLXqVbMQhaPyT","tool":"read","id":"prt_b94b6e0b3001mCVItg2EJfPAB2","messageID":"msg_b94b6d14b001y9ggcfX7Qmvfb4","state":{"status":"completed","output":"\n00001| return {\n00002| \"sudo-tee/opencode.nvim\",\n00003| config = function()\n00004| -- Check if custom configs are enabled\n00005| local custom_enabled = vim.g.opencode_custom_enabled == true\n00006| \n00007| if custom_enabled then\n00008| -- =========================================================================\n00009| -- CUSTOM CONFIGURATION MODE\n00010| -- =========================================================================\n00011| require(\"opencode\").setup({\n00012| default_mode = \"plan\", -- Default to Plan mode instead of Build\n00013| keymap = {\n00014| editor = {\n00015| [\"o\"] = { \"switch_mode\", desc = \"Toggle agent (Plan/Build)\" },\n00016| [\"ou\"] = { \"undo\", desc = \"Undo last message\" },\n00017| [\"o\"] = { \"redo\", desc = \"Redo message\" },\n00018| -- Override default provider switcher with custom favorites\n00019| [\"op\"] = {\n00020| function()\n00021| require(\"gmati.plugins.ai.opencode_favorites\").select_favorite_provider()\n00022| end,\n00023| desc = \"Switch provider (favorites)\",\n00024| },\n00025| },\n00026| input_window = {\n00027| -- Enter submits only in normal mode\n00028| [\"\"] = { \"submit_input_prompt\", mode = \"n\" },\n00029| },\n00030| },\n00031| ui = {\n00032| -- Disable built-in status displays (we use lualine instead)\n00033| display_model = false,\n00034| display_context_size = false,\n00035| display_cost = false,\n00036| },\n00037| debug = {\n00038| capture_streamed_events = true\n00039| }\n00040| })\n00041| \n00042| -- Apply UI patches to customize OpenCode rendering\n00043| vim.defer_fn(function()\n00044| require(\"gmati.plugins.ai.opencode_ui_patches\").apply_all()\n00045| end, 0)\n00046| \n00047| -- Setup custom keymaps (mode switching, diagnostics, emergency)\n00048| require(\"gmati.plugins.ai.opencode_keymaps\").setup()\n00049| \n00050| -- Setup diagnostics monitoring (health checks, error tracking)\n00051| vim.defer_fn(function()\n00052| local ok, diagnostics = pcall(require, \"gmati.plugins.ai.opencode_diagnostics\")\n00053| if ok then\n00054| diagnostics.setup()\n00055| end\n00056| end, 300)\n00057| \n00058| -- Setup LSP/features integration (disable during thinking)\n00059| vim.defer_fn(function()\n00060| local ok, integration = pcall(require, \"gmati.plugins.ai.opencode_integration\")\n00061| if ok then\n00062| integration.setup()\n00063| end\n00064| end, 200)\n00065| \n00066| -- Cleanup on exit\n00067| vim.api.nvim_create_autocmd(\"VimLeavePre\", {\n00068| callback = function()\n00069| local ok, integration = pcall(require, \"gmati.plugins.ai.opencode_integration\")\n00070| if ok then\n00071| integration.cleanup()\n00072| end\n00073| \n00074| local ok_diag, diagnostics = pcall(require, \"gmati.plugins.ai.opencode_diagnostics\")\n00075| if ok_diag then\n00076| diagnostics.cleanup()\n00077| end\n00078| end,\n00079| })\n00080| else\n00081| -- =========================================================================\n00082| -- VANILLA CONFIGURATION MODE\n00083| -- =========================================================================\n00084| require(\"opencode\").setup({\n00085| default_mode = \"plan\", -- Keep your default mode preference\n00086| debug = {\n00087| capture_streamed_events = true\n00088| }\n00089| })\n00090| end\n00091| end,\n00092| dependencies = {\n00093| \"nvim-lua/plenary.nvim\",\n00094| {\n00095| \"MeanderingProgrammer/render-markdown.nvim\",\n00096| opts = {\n00097| anti_conceal = { enabled = false },\n00098| file_types = { \"markdown\", \"opencode_output\" },\n00099| },\n00100| ft = { \"markdown\", \"Avante\", \"copilot-chat\", \"opencode_output\" },\n00101| },\n00102| -- Optional, for file mentions and commands completion\n00103| \"hrsh7th/nvim-cmp\",\n00104| -- Optional, for file mentions picker\n00105| \"folke/snacks.nvim\",\n00106| },\n00107| }\n00108| \n\n(End of file - total 108 lines)\n","metadata":{"preview":"return {\n \"sudo-tee/opencode.nvim\",\n config = function()\n -- Check if custom configs are enabled\n local custom_enabled = vim.g.opencode_custom_enabled == true\n\n if custom_enabled then\n -- =========================================================================\n -- CUSTOM CONFIGURATION MODE\n -- =========================================================================\n require(\"opencode\").setup({\n default_mode = \"plan\", -- Default to Plan mode instead of Build\n keymap = {\n editor = {\n [\"o\"] = { \"switch_mode\", desc = \"Toggle agent (Plan/Build)\" },\n [\"ou\"] = { \"undo\", desc = \"Undo last message\" },\n [\"o\"] = { \"redo\", desc = \"Redo message\" },\n -- Override default provider switcher with custom favorites\n [\"op\"] = {\n function()"},"input":{"filePath":"/Users/matigreen/dotfiles/nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua"},"time":{"start":1767726572684,"end":1767726572708},"title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua"}}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","callID":"toolu_017Li9bzxEHcp7pwBxRu4MxU","tool":"task","id":"prt_b94b6b5f3001JaaXlpjO9TFn2O","messageID":"msg_b94b6948d002pFurK7t7q4bSyb","state":{"title":"Debug alt-M keybind issue","metadata":{"summary":[{"tool":"read","id":"prt_b94b6e0b3001mCVItg2EJfPAB2","state":{"status":"completed","title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua"}},{"tool":"read","id":"prt_b94b6e4a1001n0heEU3dEGxfWa","state":{"status":"pending"}}],"sessionId":"ses_46b492ebbffel5oIJ1qUl9GKFh"},"input":{"subagent_type":"nvim","prompt":"The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.","description":"Debug alt-M keybind issue"},"time":{"start":1767726572710},"status":"running"}}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","callID":"toolu_01NLzNf8fQ5m6CbQmJi61LHi","tool":"read","id":"prt_b94b6e4a1001n0heEU3dEGxfWa","messageID":"msg_b94b6d14b001y9ggcfX7Qmvfb4","state":{"input":{},"raw":"","status":"pending"}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","callID":"toolu_01NLzNf8fQ5m6CbQmJi61LHi","tool":"read","id":"prt_b94b6e4a1001n0heEU3dEGxfWa","messageID":"msg_b94b6d14b001y9ggcfX7Qmvfb4","state":{"status":"completed","output":"\n00001| -- OpenCode Keymaps\n00002| -- All custom keybindings for OpenCode functionality\n00003| -- Organized by category for easy discovery and modification\n00004| \n00005| local M = {}\n00006| \n00007| -- Setup all OpenCode keymaps\n00008| function M.setup()\n00009| M.setup_mode_keymaps()\n00010| M.setup_diagnostic_keymaps()\n00011| M.setup_emergency_keymaps()\n00012| end\n00013| \n00014| -- Mode-related keymaps (switching modes, quick build)\n00015| function M.setup_mode_keymaps()\n00016| -- Quick build mode: Switch to build mode and prepare \"build\" command\n00017| vim.keymap.set(\"n\", \"o\", function()\n00018| require(\"gmati.plugins.ai.opencode_build_mode\").quick_build()\n00019| end, { desc = \"Build mode + prepare 'build'\" })\n00020| end\n00021| \n00022| -- Diagnostic keymaps (health status, logs)\n00023| function M.setup_diagnostic_keymaps()\n00024| -- Show OpenCode diagnostics (health status)\n00025| vim.keymap.set(\"n\", \"od\", function()\n00026| local ok, diagnostics = pcall(require, \"gmati.plugins.ai.opencode_diagnostics\")\n00027| if ok then\n00028| diagnostics.show_health_status()\n00029| else\n00030| vim.notify(\"Failed to load OpenCode diagnostics\", vim.log.levels.ERROR)\n00031| end\n00032| end, { desc = \"Show OpenCode diagnostics\" })\n00033| \n00034| -- Open OpenCode server logs\n00035| vim.keymap.set(\"n\", \"oL\", function()\n00036| local ok, diagnostics = pcall(require, \"gmati.plugins.ai.opencode_diagnostics\")\n00037| if ok then\n00038| diagnostics.open_server_logs()\n00039| else\n00040| vim.notify(\"Failed to load OpenCode diagnostics\", vim.log.levels.ERROR)\n00041| end\n00042| end, { desc = \"View OpenCode server logs\" })\n00043| end\n00044| \n00045| -- Emergency keymaps (force stop)\n00046| function M.setup_emergency_keymaps()\n00047| -- Force stop OpenCode: Nuclear option to kill all jobs and reset state\n00048| vim.keymap.set(\"n\", \"oF\", function()\n00049| require(\"gmati.plugins.ai.opencode_force_stop\").force_stop()\n00050| end, { desc = \"Force stop OpenCode (nuclear option)\" })\n00051| end\n00052| \n00053| return M\n00054| \n\n(End of file - total 54 lines)\n","metadata":{"preview":"-- OpenCode Keymaps\n-- All custom keybindings for OpenCode functionality\n-- Organized by category for easy discovery and modification\n\nlocal M = {}\n\n-- Setup all OpenCode keymaps\nfunction M.setup()\n M.setup_mode_keymaps()\n M.setup_diagnostic_keymaps()\n M.setup_emergency_keymaps()\nend\n\n-- Mode-related keymaps (switching modes, quick build)\nfunction M.setup_mode_keymaps()\n -- Quick build mode: Switch to build mode and prepare \"build\" command\n vim.keymap.set(\"n\", \"o\", function()\n require(\"gmati.plugins.ai.opencode_build_mode\").quick_build()\n end, { desc = \"Build mode + prepare 'build'\" })\nend"},"input":{"filePath":"/Users/matigreen/dotfiles/nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"},"time":{"start":1767726573388,"end":1767726573393},"title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"}}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","callID":"toolu_017Li9bzxEHcp7pwBxRu4MxU","tool":"task","id":"prt_b94b6b5f3001JaaXlpjO9TFn2O","messageID":"msg_b94b6948d002pFurK7t7q4bSyb","state":{"title":"Debug alt-M keybind issue","metadata":{"summary":[{"tool":"read","id":"prt_b94b6e0b3001mCVItg2EJfPAB2","state":{"status":"completed","title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua"}},{"tool":"read","id":"prt_b94b6e4a1001n0heEU3dEGxfWa","state":{"status":"completed","title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"}},{"tool":"read","id":"prt_b94b6e768001nwQ5wgnzVRZL8B","state":{"status":"pending"}}],"sessionId":"ses_46b492ebbffel5oIJ1qUl9GKFh"},"input":{"subagent_type":"nvim","prompt":"The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.","description":"Debug alt-M keybind issue"},"time":{"start":1767726573417},"status":"running"}}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","callID":"toolu_01SkSniBkbNnBeJr1jwfEvvs","tool":"read","id":"prt_b94b6e768001nwQ5wgnzVRZL8B","messageID":"msg_b94b6d14b001y9ggcfX7Qmvfb4","state":{"input":{},"raw":"","status":"pending"}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","callID":"toolu_01SkSniBkbNnBeJr1jwfEvvs","tool":"read","id":"prt_b94b6e768001nwQ5wgnzVRZL8B","messageID":"msg_b94b6d14b001y9ggcfX7Qmvfb4","state":{"status":"completed","output":"\n00001| initial-window = false\n00002| \n00003| quick-terminal-position = center\n00004| quick-terminal-size = 98%,95%\n00005| \n00006| window-padding-x = 16\n00007| window-padding-y = 16\n00008| window-padding-balance = true\n00009| \n00010| theme = catppuccin-mocha.conf\n00011| background-opacity = 0.9\n00012| background-blur-radius = 20\n00013| \n00014| font-family = \"Hack Nerd Font\"\n00015| font-size = 18\n00016| \n00017| # Enable Option key as Alt modifier for terminal keybindings\n00018| macos-option-as-alt = true\n00019| \n00020| keybind = global:cmd+f12=toggle_quick_terminal\n00021| \n00022| keybind = cmd+shift+k=goto_split:top\n00023| keybind = cmd+shift+j=goto_split:bottom\n00024| keybind = cmd+shift+h=goto_split:left\n00025| keybind = cmd+shift+l=goto_split:right\n00026| \n\n(End of file - total 26 lines)\n","metadata":{"preview":"initial-window = false\n\nquick-terminal-position = center\nquick-terminal-size = 98%,95%\n\nwindow-padding-x = 16\nwindow-padding-y = 16\nwindow-padding-balance = true\n\ntheme = catppuccin-mocha.conf\nbackground-opacity = 0.9\nbackground-blur-radius = 20\n\nfont-family = \"Hack Nerd Font\"\nfont-size = 18\n\n# Enable Option key as Alt modifier for terminal keybindings\nmacos-option-as-alt = true\n\nkeybind = global:cmd+f12=toggle_quick_terminal"},"input":{"filePath":"/Users/matigreen/dotfiles/ghostty/.config/ghostty/config"},"time":{"start":1767726573681,"end":1767726573695},"title":"ghostty/.config/ghostty/config"}}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","callID":"toolu_017Li9bzxEHcp7pwBxRu4MxU","tool":"task","id":"prt_b94b6b5f3001JaaXlpjO9TFn2O","messageID":"msg_b94b6948d002pFurK7t7q4bSyb","state":{"title":"Debug alt-M keybind issue","metadata":{"summary":[{"tool":"read","id":"prt_b94b6e0b3001mCVItg2EJfPAB2","state":{"status":"completed","title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua"}},{"tool":"read","id":"prt_b94b6e4a1001n0heEU3dEGxfWa","state":{"status":"completed","title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"}},{"tool":"read","id":"prt_b94b6e768001nwQ5wgnzVRZL8B","state":{"status":"completed","title":"ghostty/.config/ghostty/config"}}],"sessionId":"ses_46b492ebbffel5oIJ1qUl9GKFh"},"input":{"subagent_type":"nvim","prompt":"The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.","description":"Debug alt-M keybind issue"},"time":{"start":1767726573696},"status":"running"}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"step-finish","snapshot":"29b76c5b84a59e892d23447cd82abb3afea86e41","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","reason":"tool-calls","messageID":"msg_b94b6d14b001y9ggcfX7Qmvfb4","id":"prt_b94b6e910001sHfwoYXshpCwWv","cost":0,"tokens":{"reasoning":0,"input":2,"output":235,"cache":{"write":24673,"read":0}}}}},{"type":"message.updated","properties":{"info":{"role":"assistant","finish":"tool-calls","tokens":{"reasoning":0,"input":2,"output":235,"cache":{"write":24673,"read":0}},"parentID":"msg_b94b6d147001k2DbeF1m2JpIP3","providerID":"anthropic","time":{"created":1767726567755},"id":"msg_b94b6d14b001y9ggcfX7Qmvfb4","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","modelID":"claude-sonnet-4-5","mode":"nvim","cost":0,"agent":"nvim","path":{"cwd":"/Users/matigreen/dotfiles","root":"/Users/matigreen/dotfiles"}}}},{"type":"message.updated","properties":{"info":{"role":"assistant","finish":"tool-calls","tokens":{"reasoning":0,"input":2,"output":235,"cache":{"write":24673,"read":0}},"parentID":"msg_b94b6d147001k2DbeF1m2JpIP3","providerID":"anthropic","time":{"created":1767726567755,"completed":1767726573914},"id":"msg_b94b6d14b001y9ggcfX7Qmvfb4","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","modelID":"claude-sonnet-4-5","mode":"nvim","cost":0,"agent":"nvim","path":{"cwd":"/Users/matigreen/dotfiles","root":"/Users/matigreen/dotfiles"}}}},{"type":"message.updated","properties":{"info":{"role":"assistant","tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"parentID":"msg_b94b6d147001k2DbeF1m2JpIP3","providerID":"anthropic","time":{"created":1767726573918},"id":"msg_b94b6e95e001xIoTqqCWgaqBfO","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","modelID":"claude-sonnet-4-5","mode":"nvim","cost":0,"agent":"nvim","path":{"cwd":"/Users/matigreen/dotfiles","root":"/Users/matigreen/dotfiles"}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"role":"user","summary":{"title":"Debugging alt-M keybind opencode.nvim","diffs":[]},"sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","tools":{"todoread":false,"task":false,"browser_*":false,"atlassian_*":false,"jira_get":true,"confluence_*":false,"todowrite":false,"playwright":false,"write":true,"edit":true,"bash":true},"time":{"created":1767726567752},"id":"msg_b94b6d147001k2DbeF1m2JpIP3","agent":"nvim","model":{"providerID":"anthropic","modelID":"claude-sonnet-4-5"}}}},{"type":"session.updated","properties":{"info":{"projectID":"b8136e83cf077521b7177c9660d223a1759f881e","title":"Debug alt-M keybind issue (@nvim subagent)","version":"1.0.220","time":{"created":1767726567748,"updated":1767726573935},"directory":"/Users/matigreen/dotfiles","parentID":"ses_46b499f08ffe3aldWmWZoH6N2m","summary":{"deletions":0,"files":0,"additions":0},"id":"ses_46b492ebbffel5oIJ1qUl9GKFh"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"step-start","snapshot":"29b76c5b84a59e892d23447cd82abb3afea86e41","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","id":"prt_b94b6f600001vrOB25LzH46DAo","messageID":"msg_b94b6e95e001xIoTqqCWgaqBfO"}}},{"type":"message.part.updated","properties":{"delta":" let","part":{"type":"text","text":"Now let","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","id":"prt_b94b6f601001imJME5kdm4mlg6","time":{"start":1767726577153},"messageID":"msg_b94b6e95e001xIoTqqCWgaqBfO"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":"code.","part":{"type":"text","text":"Now let me check the opencode.","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","id":"prt_b94b6f601001imJME5kdm4mlg6","time":{"start":1767726577153},"messageID":"msg_b94b6e95e001xIoTqqCWgaqBfO"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":" or","part":{"type":"text","text":"Now let me check the opencode.nvim plugin documentation or","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","id":"prt_b94b6f601001imJME5kdm4mlg6","time":{"start":1767726577153},"messageID":"msg_b94b6e95e001xIoTqqCWgaqBfO"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":" default","part":{"type":"text","text":"Now let me check the opencode.nvim plugin documentation or source to understand what the default","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","id":"prt_b94b6f601001imJME5kdm4mlg6","time":{"start":1767726577153},"messageID":"msg_b94b6e95e001xIoTqqCWgaqBfO"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":"alt","part":{"type":"text","text":"Now let me check the opencode.nvim plugin documentation or source to understand what the default `alt","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","id":"prt_b94b6f601001imJME5kdm4mlg6","time":{"start":1767726577153},"messageID":"msg_b94b6e95e001xIoTqqCWgaqBfO"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":"` ke","part":{"type":"text","text":"Now let me check the opencode.nvim plugin documentation or source to understand what the default `alt-M` ke","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","id":"prt_b94b6f601001imJME5kdm4mlg6","time":{"start":1767726577153},"messageID":"msg_b94b6e95e001xIoTqqCWgaqBfO"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"delta":"d does","part":{"type":"text","text":"Now let me check the opencode.nvim plugin documentation or source to understand what the default `alt-M` keybind does","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","id":"prt_b94b6f601001imJME5kdm4mlg6","time":{"start":1767726577153},"messageID":"msg_b94b6e95e001xIoTqqCWgaqBfO"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","text":"Now let me check the opencode.nvim plugin documentation or source to understand what the default `alt-M` keybind does:","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","id":"prt_b94b6f601001imJME5kdm4mlg6","time":{"start":1767726578336,"end":1767726578336},"messageID":"msg_b94b6e95e001xIoTqqCWgaqBfO"}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","callID":"toolu_0135HE3hqPJhMmqYtvzz2xyu","tool":"bash","id":"prt_b94b6faa0001LKlGQTIabbHKvg","messageID":"msg_b94b6e95e001xIoTqqCWgaqBfO","state":{"input":{},"raw":"","status":"pending"}}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","callID":"toolu_017Li9bzxEHcp7pwBxRu4MxU","tool":"task","id":"prt_b94b6b5f3001JaaXlpjO9TFn2O","messageID":"msg_b94b6948d002pFurK7t7q4bSyb","state":{"title":"Debug alt-M keybind issue","metadata":{"summary":[{"tool":"read","id":"prt_b94b6e0b3001mCVItg2EJfPAB2","state":{"status":"completed","title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua"}},{"tool":"read","id":"prt_b94b6e4a1001n0heEU3dEGxfWa","state":{"status":"completed","title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"}},{"tool":"read","id":"prt_b94b6e768001nwQ5wgnzVRZL8B","state":{"status":"completed","title":"ghostty/.config/ghostty/config"}},{"tool":"bash","id":"prt_b94b6faa0001LKlGQTIabbHKvg","state":{"status":"pending"}}],"sessionId":"ses_46b492ebbffel5oIJ1qUl9GKFh"},"input":{"subagent_type":"nvim","prompt":"The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.","description":"Debug alt-M keybind issue"},"time":{"start":1767726578336},"status":"running"}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","callID":"toolu_0135HE3hqPJhMmqYtvzz2xyu","tool":"bash","id":"prt_b94b6faa0001LKlGQTIabbHKvg","messageID":"msg_b94b6e95e001xIoTqqCWgaqBfO","state":{"input":{"command":"cd ~/.local/share/nvim/lazy/opencode.nvim && find . -name \"*.lua\" -type f | head -20","description":"Find opencode.nvim plugin files"},"time":{"start":1767726579322},"status":"running"}}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","callID":"toolu_017Li9bzxEHcp7pwBxRu4MxU","tool":"task","id":"prt_b94b6b5f3001JaaXlpjO9TFn2O","messageID":"msg_b94b6948d002pFurK7t7q4bSyb","state":{"title":"Debug alt-M keybind issue","metadata":{"summary":[{"tool":"read","id":"prt_b94b6e0b3001mCVItg2EJfPAB2","state":{"status":"completed","title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua"}},{"tool":"read","id":"prt_b94b6e4a1001n0heEU3dEGxfWa","state":{"status":"completed","title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"}},{"tool":"read","id":"prt_b94b6e768001nwQ5wgnzVRZL8B","state":{"status":"completed","title":"ghostty/.config/ghostty/config"}},{"tool":"bash","id":"prt_b94b6faa0001LKlGQTIabbHKvg","state":{"status":"running"}}],"sessionId":"ses_46b492ebbffel5oIJ1qUl9GKFh"},"input":{"subagent_type":"nvim","prompt":"The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.","description":"Debug alt-M keybind issue"},"time":{"start":1767726579323},"status":"running"}}}},{"type":"permission.updated","properties":{"title":"cd ~/.local/share/nvim/lazy/opencode.nvim && find . -name \"*.lua\" -type f | head -20","pattern":["find . *","head *"],"type":"bash","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","callID":"toolu_0135HE3hqPJhMmqYtvzz2xyu","metadata":{"command":"cd ~/.local/share/nvim/lazy/opencode.nvim && find . -name \"*.lua\" -type f | head -20","patterns":["find . *","head *"]},"id":"per_b94b6fe95001R3s3aeqFb9wsLe","time":{"created":1767726579349},"messageID":"msg_b94b6e95e001xIoTqqCWgaqBfO"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"permission.replied","properties":{"permissionID":"per_b94b6fe95001R3s3aeqFb9wsLe","response":"once","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh"}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","callID":"toolu_0135HE3hqPJhMmqYtvzz2xyu","tool":"bash","id":"prt_b94b6faa0001LKlGQTIabbHKvg","messageID":"msg_b94b6e95e001xIoTqqCWgaqBfO","state":{"status":"completed","output":"./tests/mocks/session_list.lua\n./tests/unit/hooks_spec.lua\n./tests/unit/timer_spec.lua\n./tests/unit/input_window_spec.lua\n./tests/unit/server_job_spec.lua\n./tests/unit/config_spec.lua\n./tests/unit/api_spec.lua\n./tests/unit/event_manager_spec.lua\n./tests/unit/init_spec.lua\n./tests/unit/state_spec.lua\n./tests/unit/image_handler_spec.lua\n./tests/unit/id_spec.lua\n./tests/unit/api_client_spec.lua\n./tests/unit/context_spec.lua\n./tests/unit/session_spec.lua\n./tests/unit/config_file_spec.lua\n./tests/unit/opencode_server_spec.lua\n./tests/unit/core_spec.lua\n./tests/unit/context_completion_spec.lua\n./tests/unit/render_state_spec.lua\n","metadata":{"exit":0,"output":"./tests/mocks/session_list.lua\n./tests/unit/hooks_spec.lua\n./tests/unit/timer_spec.lua\n./tests/unit/input_window_spec.lua\n./tests/unit/server_job_spec.lua\n./tests/unit/config_spec.lua\n./tests/unit/api_spec.lua\n./tests/unit/event_manager_spec.lua\n./tests/unit/init_spec.lua\n./tests/unit/state_spec.lua\n./tests/unit/image_handler_spec.lua\n./tests/unit/id_spec.lua\n./tests/unit/api_client_spec.lua\n./tests/unit/context_spec.lua\n./tests/unit/session_spec.lua\n./tests/unit/config_file_spec.lua\n./tests/unit/opencode_server_spec.lua\n./tests/unit/core_spec.lua\n./tests/unit/context_completion_spec.lua\n./tests/unit/render_state_spec.lua\n","description":"Find opencode.nvim plugin files"},"input":{"command":"cd ~/.local/share/nvim/lazy/opencode.nvim && find . -name \"*.lua\" -type f | head -20","description":"Find opencode.nvim plugin files"},"time":{"start":1767726579322,"end":1767726603966},"title":"Find opencode.nvim plugin files"}}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","callID":"toolu_017Li9bzxEHcp7pwBxRu4MxU","tool":"task","id":"prt_b94b6b5f3001JaaXlpjO9TFn2O","messageID":"msg_b94b6948d002pFurK7t7q4bSyb","state":{"title":"Debug alt-M keybind issue","metadata":{"summary":[{"tool":"read","id":"prt_b94b6e0b3001mCVItg2EJfPAB2","state":{"status":"completed","title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua"}},{"tool":"read","id":"prt_b94b6e4a1001n0heEU3dEGxfWa","state":{"status":"completed","title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"}},{"tool":"read","id":"prt_b94b6e768001nwQ5wgnzVRZL8B","state":{"status":"completed","title":"ghostty/.config/ghostty/config"}},{"tool":"bash","id":"prt_b94b6faa0001LKlGQTIabbHKvg","state":{"status":"completed","title":"Find opencode.nvim plugin files"}}],"sessionId":"ses_46b492ebbffel5oIJ1qUl9GKFh"},"input":{"subagent_type":"nvim","prompt":"The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.","description":"Debug alt-M keybind issue"},"time":{"start":1767726603967},"status":"running"}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"step-finish","snapshot":"29b76c5b84a59e892d23447cd82abb3afea86e41","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","reason":"tool-calls","messageID":"msg_b94b6e95e001xIoTqqCWgaqBfO","id":"prt_b94b75ec0001Fsf2UjpQApsRHh","cost":0,"tokens":{"reasoning":0,"input":6,"output":136,"cache":{"write":2712,"read":24673}}}}},{"type":"message.updated","properties":{"info":{"role":"assistant","finish":"tool-calls","tokens":{"reasoning":0,"input":6,"output":136,"cache":{"write":2712,"read":24673}},"parentID":"msg_b94b6d147001k2DbeF1m2JpIP3","providerID":"anthropic","time":{"created":1767726573918},"id":"msg_b94b6e95e001xIoTqqCWgaqBfO","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","modelID":"claude-sonnet-4-5","mode":"nvim","cost":0,"agent":"nvim","path":{"cwd":"/Users/matigreen/dotfiles","root":"/Users/matigreen/dotfiles"}}}},{"type":"message.updated","properties":{"info":{"role":"assistant","finish":"tool-calls","tokens":{"reasoning":0,"input":6,"output":136,"cache":{"write":2712,"read":24673}},"parentID":"msg_b94b6d147001k2DbeF1m2JpIP3","providerID":"anthropic","time":{"created":1767726573918,"completed":1767726604035},"id":"msg_b94b6e95e001xIoTqqCWgaqBfO","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","modelID":"claude-sonnet-4-5","mode":"nvim","cost":0,"agent":"nvim","path":{"cwd":"/Users/matigreen/dotfiles","root":"/Users/matigreen/dotfiles"}}}},{"type":"message.updated","properties":{"info":{"role":"assistant","tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"parentID":"msg_b94b6d147001k2DbeF1m2JpIP3","providerID":"anthropic","time":{"created":1767726604039},"id":"msg_b94b75f07001FvPfzM3IrqRHw3","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","modelID":"claude-sonnet-4-5","mode":"nvim","cost":0,"agent":"nvim","path":{"cwd":"/Users/matigreen/dotfiles","root":"/Users/matigreen/dotfiles"}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"session.updated","properties":{"info":{"projectID":"b8136e83cf077521b7177c9660d223a1759f881e","title":"Debug alt-M keybind issue (@nvim subagent)","version":"1.0.220","time":{"created":1767726567748,"updated":1767726604056},"directory":"/Users/matigreen/dotfiles","parentID":"ses_46b499f08ffe3aldWmWZoH6N2m","summary":{"deletions":0,"files":0,"additions":0},"id":"ses_46b492ebbffel5oIJ1qUl9GKFh"}}},{"type":"message.updated","properties":{"info":{"role":"user","summary":{"title":"Debugging alt-M keybind opencode.nvim","diffs":[]},"sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","tools":{"todoread":false,"task":false,"browser_*":false,"atlassian_*":false,"jira_get":true,"confluence_*":false,"todowrite":false,"playwright":false,"write":true,"edit":true,"bash":true},"time":{"created":1767726567752},"id":"msg_b94b6d147001k2DbeF1m2JpIP3","agent":"nvim","model":{"providerID":"anthropic","modelID":"claude-sonnet-4-5"}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"step-start","snapshot":"29b76c5b84a59e892d23447cd82abb3afea86e41","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","id":"prt_b94b76a1d001uetcdCGKMa7pGM","messageID":"msg_b94b75f07001FvPfzM3IrqRHw3"}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","callID":"toolu_01XNzaXKr6tXjYSfRSikTw7Z","tool":"bash","id":"prt_b94b76a20001J4RYEL24y0dMrZ","messageID":"msg_b94b75f07001FvPfzM3IrqRHw3","state":{"input":{},"raw":"","status":"pending"}}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","callID":"toolu_017Li9bzxEHcp7pwBxRu4MxU","tool":"task","id":"prt_b94b6b5f3001JaaXlpjO9TFn2O","messageID":"msg_b94b6948d002pFurK7t7q4bSyb","state":{"title":"Debug alt-M keybind issue","metadata":{"summary":[{"tool":"read","id":"prt_b94b6e0b3001mCVItg2EJfPAB2","state":{"status":"completed","title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua"}},{"tool":"read","id":"prt_b94b6e4a1001n0heEU3dEGxfWa","state":{"status":"completed","title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"}},{"tool":"read","id":"prt_b94b6e768001nwQ5wgnzVRZL8B","state":{"status":"completed","title":"ghostty/.config/ghostty/config"}},{"tool":"bash","id":"prt_b94b6faa0001LKlGQTIabbHKvg","state":{"status":"completed","title":"Find opencode.nvim plugin files"}},{"tool":"bash","id":"prt_b94b76a20001J4RYEL24y0dMrZ","state":{"status":"pending"}}],"sessionId":"ses_46b492ebbffel5oIJ1qUl9GKFh"},"input":{"subagent_type":"nvim","prompt":"The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.","description":"Debug alt-M keybind issue"},"time":{"start":1767726606880},"status":"running"}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","callID":"toolu_01XNzaXKr6tXjYSfRSikTw7Z","tool":"bash","id":"prt_b94b76a20001J4RYEL24y0dMrZ","messageID":"msg_b94b75f07001FvPfzM3IrqRHw3","state":{"input":{"command":"cd ~/.local/share/nvim/lazy/opencode.nvim && grep -r \"alt-M\\|\" --include=\"*.lua\" | head -20","description":"Search for alt-M keybind in opencode.nvim"},"time":{"start":1767726607982},"status":"running"}}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","sessionID":"ses_46b499f08ffe3aldWmWZoH6N2m","callID":"toolu_017Li9bzxEHcp7pwBxRu4MxU","tool":"task","id":"prt_b94b6b5f3001JaaXlpjO9TFn2O","messageID":"msg_b94b6948d002pFurK7t7q4bSyb","state":{"title":"Debug alt-M keybind issue","metadata":{"summary":[{"tool":"read","id":"prt_b94b6e0b3001mCVItg2EJfPAB2","state":{"status":"completed","title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua"}},{"tool":"read","id":"prt_b94b6e4a1001n0heEU3dEGxfWa","state":{"status":"completed","title":"nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"}},{"tool":"read","id":"prt_b94b6e768001nwQ5wgnzVRZL8B","state":{"status":"completed","title":"ghostty/.config/ghostty/config"}},{"tool":"bash","id":"prt_b94b6faa0001LKlGQTIabbHKvg","state":{"status":"completed","title":"Find opencode.nvim plugin files"}},{"tool":"bash","id":"prt_b94b76a20001J4RYEL24y0dMrZ","state":{"status":"running"}}],"sessionId":"ses_46b492ebbffel5oIJ1qUl9GKFh"},"input":{"subagent_type":"nvim","prompt":"The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.","description":"Debug alt-M keybind issue"},"time":{"start":1767726607982},"status":"running"}}}},{"type":"permission.updated","properties":{"title":"cd ~/.local/share/nvim/lazy/opencode.nvim && grep -r \"alt-M\\|\" --include=\"*.lua\" | head -20","pattern":["grep \"alt-M\\|\" *","head *"],"type":"bash","sessionID":"ses_46b492ebbffel5oIJ1qUl9GKFh","callID":"toolu_01XNzaXKr6tXjYSfRSikTw7Z","metadata":{"command":"cd ~/.local/share/nvim/lazy/opencode.nvim && grep -r \"alt-M\\|\" --include=\"*.lua\" | head -20","patterns":["grep \"alt-M\\|\" *","head *"]},"id":"per_b94b76e73001ml5seBvInCYYHG","time":{"created":1767726607987},"messageID":"msg_b94b75f07001FvPfzM3IrqRHw3"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]}]
+[
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "user",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "agent": "plan",
+ "id": "msg_b94b69474001IGYFIs72LkX50a",
+ "time": { "created": 1767726552181 },
+ "model": { "providerID": "anthropic", "modelID": "claude-sonnet-4-5" }
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "agent",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "messageID": "msg_b94b69474001IGYFIs72LkX50a",
+ "id": "prt_b94b69475001ahJ6Yfg4gUhw5v",
+ "source": { "end": 5, "value": "@nvim", "start": 0 },
+ "name": "nvim"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "text": "Use the above message and context to generate a prompt and call the task tool with subagent: nvim",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "synthetic": true,
+ "id": "prt_b94b69475002LiAJbv6BRaVSpQ",
+ "messageID": "msg_b94b69474001IGYFIs72LkX50a"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "text": "Called the Read tool with the following input: {\"filePath\":\"/Users/matigreen/dotfiles/nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua\"}",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "synthetic": true,
+ "id": "prt_b94b69475004x7HkswYBcQhl62",
+ "messageID": "msg_b94b69474001IGYFIs72LkX50a"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "text": "\n00001| return {\n00002| \"sudo-tee/opencode.nvim\",\n00003| config = function()\n00004| -- Check if custom configs are enabled\n00005| local custom_enabled = vim.g.opencode_custom_enabled == true\n00006| \n00007| if custom_enabled then\n00008| -- =========================================================================\n00009| -- CUSTOM CONFIGURATION MODE\n00010| -- =========================================================================\n00011| require(\"opencode\").setup({\n00012| default_mode = \"plan\", -- Default to Plan mode instead of Build\n00013| keymap = {\n00014| editor = {\n00015| [\"o\"] = { \"switch_mode\", desc = \"Toggle agent (Plan/Build)\" },\n00016| [\"ou\"] = { \"undo\", desc = \"Undo last message\" },\n00017| [\"o\"] = { \"redo\", desc = \"Redo message\" },\n00018| -- Override default provider switcher with custom favorites\n00019| [\"op\"] = {\n00020| function()\n00021| require(\"gmati.plugins.ai.opencode_favorites\").select_favorite_provider()\n00022| end,\n00023| desc = \"Switch provider (favorites)\",\n00024| },\n00025| },\n00026| input_window = {\n00027| -- Enter submits only in normal mode\n00028| [\"\"] = { \"submit_input_prompt\", mode = \"n\" },\n00029| },\n00030| },\n00031| ui = {\n00032| -- Disable built-in status displays (we use lualine instead)\n00033| display_model = false,\n00034| display_context_size = false,\n00035| display_cost = false,\n00036| },\n00037| debug = {\n00038| capture_streamed_events = true\n00039| }\n00040| })\n00041| \n00042| -- Apply UI patches to customize OpenCode rendering\n00043| vim.defer_fn(function()\n00044| require(\"gmati.plugins.ai.opencode_ui_patches\").apply_all()\n00045| end, 0)\n00046| \n00047| -- Setup custom keymaps (mode switching, diagnostics, emergency)\n00048| require(\"gmati.plugins.ai.opencode_keymaps\").setup()\n00049| \n00050| -- Setup diagnostics monitoring (health checks, error tracking)\n00051| vim.defer_fn(function()\n00052| local ok, diagnostics = pcall(require, \"gmati.plugins.ai.opencode_diagnostics\")\n00053| if ok then\n00054| diagnostics.setup()\n00055| end\n00056| end, 300)\n00057| \n00058| -- Setup LSP/features integration (disable during thinking)\n00059| vim.defer_fn(function()\n00060| local ok, integration = pcall(require, \"gmati.plugins.ai.opencode_integration\")\n00061| if ok then\n00062| integration.setup()\n00063| end\n00064| end, 200)\n00065| \n00066| -- Cleanup on exit\n00067| vim.api.nvim_create_autocmd(\"VimLeavePre\", {\n00068| callback = function()\n00069| local ok, integration = pcall(require, \"gmati.plugins.ai.opencode_integration\")\n00070| if ok then\n00071| integration.cleanup()\n00072| end\n00073| \n00074| local ok_diag, diagnostics = pcall(require, \"gmati.plugins.ai.opencode_diagnostics\")\n00075| if ok_diag then\n00076| diagnostics.cleanup()\n00077| end\n00078| end,\n00079| })\n00080| else\n00081| -- =========================================================================\n00082| -- VANILLA CONFIGURATION MODE\n00083| -- =========================================================================\n00084| require(\"opencode\").setup({\n00085| default_mode = \"plan\", -- Keep your default mode preference\n00086| debug = {\n00087| capture_streamed_events = true\n00088| }\n00089| })\n00090| end\n00091| end,\n00092| dependencies = {\n00093| \"nvim-lua/plenary.nvim\",\n00094| {\n00095| \"MeanderingProgrammer/render-markdown.nvim\",\n00096| opts = {\n00097| anti_conceal = { enabled = false },\n00098| file_types = { \"markdown\", \"opencode_output\" },\n00099| },\n00100| ft = { \"markdown\", \"Avante\", \"copilot-chat\", \"opencode_output\" },\n00101| },\n00102| -- Optional, for file mentions and commands completion\n00103| \"hrsh7th/nvim-cmp\",\n00104| -- Optional, for file mentions picker\n00105| \"folke/snacks.nvim\",\n00106| },\n00107| }\n00108| \n\n(End of file - total 108 lines)\n",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "synthetic": true,
+ "id": "prt_b94b69478001tl1GxEgWIuCfyD",
+ "messageID": "msg_b94b69474001IGYFIs72LkX50a"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "file",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "url": "file:///Users/matigreen/dotfiles/nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua",
+ "filename": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua",
+ "id": "prt_b94b694780020D1il48agKCnJG",
+ "messageID": "msg_b94b69474001IGYFIs72LkX50a",
+ "mime": "text/plain"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "text": "@nvim my alt-M keybind does not work for opencode.nvim plugin for nvim, but it is the default keymap of the plugin\n",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "id": "prt_b94b694750033Bhav31Nb5Zl3j",
+ "messageID": "msg_b94b69474001IGYFIs72LkX50a"
+ }
+ }
+ },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "title": "New session - 2026-01-06T19:08:58.999Z",
+ "version": "1.0.220",
+ "directory": "/Users/matigreen/dotfiles",
+ "id": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "time": { "created": 1767726538999, "updated": 1767726552190 },
+ "projectID": "b8136e83cf077521b7177c9660d223a1759f881e"
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "assistant",
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "parentID": "msg_b94b69474001IGYFIs72LkX50a",
+ "providerID": "anthropic",
+ "time": { "created": 1767726552205 },
+ "id": "msg_b94b6948d002pFurK7t7q4bSyb",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "modelID": "claude-sonnet-4-5",
+ "mode": "plan",
+ "cost": 0,
+ "agent": "plan",
+ "path": { "cwd": "/Users/matigreen/dotfiles", "root": "/Users/matigreen/dotfiles" }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "title": "Debugging Alt-M keybind in opencode.nvim",
+ "version": "1.0.220",
+ "directory": "/Users/matigreen/dotfiles",
+ "id": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "time": { "created": 1767726538999, "updated": 1767726553777 },
+ "projectID": "b8136e83cf077521b7177c9660d223a1759f881e"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "user",
+ "summary": { "diffs": [] },
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "time": { "created": 1767726552181 },
+ "id": "msg_b94b69474001IGYFIs72LkX50a",
+ "agent": "plan",
+ "model": { "providerID": "anthropic", "modelID": "claude-sonnet-4-5" }
+ }
+ }
+ },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "title": "Debugging Alt-M keybind in opencode.nvim",
+ "version": "1.0.220",
+ "projectID": "b8136e83cf077521b7177c9660d223a1759f881e",
+ "directory": "/Users/matigreen/dotfiles",
+ "id": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "summary": { "deletions": 0, "files": 0, "additions": 0 },
+ "time": { "created": 1767726538999, "updated": 1767726554586 }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "user",
+ "summary": { "title": "Debugging alt-M keybind in opencode.nvim", "diffs": [] },
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "system": "# Code References\n\n**CRITICAL: Always use the file:// URI scheme when referencing files in responses AND wrap them in backticks.**\n\nFormat: `file://path/to/file.lua`, `file://path/to/file.lua:42`, or `file://path/to/file.lua:42-50`\n\nExamples:\n- CORRECT: \"The error is in `file://src/services/process.ts:712`\"\n- INCORRECT: \"The error is in file://src/services/process.ts:712\"\n- INCORRECT: \"The error is in src/services/process.ts:712\"\n\nThis matches the file:// URI format that the reference picker already parses from your responses, enabling automatic navigation.\n",
+ "time": { "created": 1767726552181 },
+ "id": "msg_b94b69474001IGYFIs72LkX50a",
+ "agent": "plan",
+ "model": { "providerID": "anthropic", "modelID": "claude-sonnet-4-5" }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "snapshot": "29b76c5b84a59e892d23447cd82abb3afea86e41",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "id": "prt_b94b6b0ad0015WllkaFXZte33S",
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": "I'll",
+ "part": {
+ "type": "text",
+ "text": "I'll",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "id": "prt_b94b6b0af001kAm5cXAFC8lXrL",
+ "time": { "start": 1767726559407 },
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": " the",
+ "part": {
+ "type": "text",
+ "text": "I'll help you investigate why the",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "id": "prt_b94b6b0af001kAm5cXAFC8lXrL",
+ "time": { "start": 1767726559407 },
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": "-",
+ "part": {
+ "type": "text",
+ "text": "I'll help you investigate why the `alt-",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "id": "prt_b94b6b0af001kAm5cXAFC8lXrL",
+ "time": { "start": 1767726559407 },
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": "M",
+ "part": {
+ "type": "text",
+ "text": "I'll help you investigate why the `alt-M",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "id": "prt_b94b6b0af001kAm5cXAFC8lXrL",
+ "time": { "start": 1767726559407 },
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": "` ke",
+ "part": {
+ "type": "text",
+ "text": "I'll help you investigate why the `alt-M` ke",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "id": "prt_b94b6b0af001kAm5cXAFC8lXrL",
+ "time": { "start": 1767726559407 },
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": "ybin",
+ "part": {
+ "type": "text",
+ "text": "I'll help you investigate why the `alt-M` keybin",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "id": "prt_b94b6b0af001kAm5cXAFC8lXrL",
+ "time": { "start": 1767726559407 },
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": " open",
+ "part": {
+ "type": "text",
+ "text": "I'll help you investigate why the `alt-M` keybind isn't working for the open",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "id": "prt_b94b6b0af001kAm5cXAFC8lXrL",
+ "time": { "start": 1767726559407 },
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": "code.",
+ "part": {
+ "type": "text",
+ "text": "I'll help you investigate why the `alt-M` keybind isn't working for the opencode.",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "id": "prt_b94b6b0af001kAm5cXAFC8lXrL",
+ "time": { "start": 1767726559407 },
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": " agent",
+ "part": {
+ "type": "text",
+ "text": "I'll help you investigate why the `alt-M` keybind isn't working for the opencode.nvim plugin. Let me delegate this to the nvim specialist agent",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "id": "prt_b94b6b0af001kAm5cXAFC8lXrL",
+ "time": { "start": 1767726559407 },
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": ".",
+ "part": {
+ "type": "text",
+ "text": "I'll help you investigate why the `alt-M` keybind isn't working for the opencode.nvim plugin. Let me delegate this to the nvim specialist agent.",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "id": "prt_b94b6b0af001kAm5cXAFC8lXrL",
+ "time": { "start": 1767726559407 },
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "text": "I'll help you investigate why the `alt-M` keybind isn't working for the opencode.nvim plugin. Let me delegate this to the nvim specialist agent.",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "id": "prt_b94b6b0af001kAm5cXAFC8lXrL",
+ "time": { "start": 1767726560755, "end": 1767726560755 },
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "callID": "toolu_017Li9bzxEHcp7pwBxRu4MxU",
+ "tool": "task",
+ "id": "prt_b94b6b5f3001JaaXlpjO9TFn2O",
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb",
+ "state": { "input": {}, "raw": "", "status": "pending" }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "title": "Debug alt-M keybind issue (@nvim subagent)",
+ "version": "1.0.220",
+ "projectID": "b8136e83cf077521b7177c9660d223a1759f881e",
+ "directory": "/Users/matigreen/dotfiles",
+ "parentID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "time": { "created": 1767726567748, "updated": 1767726567748 },
+ "id": "ses_46b492ebbffel5oIJ1qUl9GKFh"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "callID": "toolu_017Li9bzxEHcp7pwBxRu4MxU",
+ "tool": "task",
+ "id": "prt_b94b6b5f3001JaaXlpjO9TFn2O",
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb",
+ "state": {
+ "title": "Debug alt-M keybind issue",
+ "metadata": { "sessionId": "ses_46b492ebbffel5oIJ1qUl9GKFh" },
+ "input": {
+ "subagent_type": "nvim",
+ "prompt": "The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.",
+ "description": "Debug alt-M keybind issue"
+ },
+ "time": { "start": 1767726567751 },
+ "status": "running"
+ }
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "user",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "tools": {
+ "todoread": false,
+ "task": false,
+ "browser_*": false,
+ "atlassian_*": false,
+ "jira_get": true,
+ "confluence_*": false,
+ "todowrite": false,
+ "playwright": false,
+ "write": true,
+ "edit": true,
+ "bash": true
+ },
+ "agent": "nvim",
+ "id": "msg_b94b6d147001k2DbeF1m2JpIP3",
+ "time": { "created": 1767726567752 },
+ "model": { "providerID": "anthropic", "modelID": "claude-sonnet-4-5" }
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "text": "The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "id": "prt_b94b6d148001ScODvsxRwAPkK7",
+ "messageID": "msg_b94b6d147001k2DbeF1m2JpIP3"
+ }
+ }
+ },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "title": "Debug alt-M keybind issue (@nvim subagent)",
+ "version": "1.0.220",
+ "projectID": "b8136e83cf077521b7177c9660d223a1759f881e",
+ "directory": "/Users/matigreen/dotfiles",
+ "parentID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "time": { "created": 1767726567748, "updated": 1767726567754 },
+ "id": "ses_46b492ebbffel5oIJ1qUl9GKFh"
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "assistant",
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "parentID": "msg_b94b6d147001k2DbeF1m2JpIP3",
+ "providerID": "anthropic",
+ "time": { "created": 1767726567755 },
+ "id": "msg_b94b6d14b001y9ggcfX7Qmvfb4",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "modelID": "claude-sonnet-4-5",
+ "mode": "nvim",
+ "cost": 0,
+ "agent": "nvim",
+ "path": { "cwd": "/Users/matigreen/dotfiles", "root": "/Users/matigreen/dotfiles" }
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "user",
+ "summary": { "diffs": [] },
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "tools": {
+ "todoread": false,
+ "task": false,
+ "browser_*": false,
+ "atlassian_*": false,
+ "jira_get": true,
+ "confluence_*": false,
+ "todowrite": false,
+ "playwright": false,
+ "write": true,
+ "edit": true,
+ "bash": true
+ },
+ "time": { "created": 1767726567752 },
+ "id": "msg_b94b6d147001k2DbeF1m2JpIP3",
+ "agent": "nvim",
+ "model": { "providerID": "anthropic", "modelID": "claude-sonnet-4-5" }
+ }
+ }
+ },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "projectID": "b8136e83cf077521b7177c9660d223a1759f881e",
+ "title": "Debug alt-M keybind issue (@nvim subagent)",
+ "version": "1.0.220",
+ "time": { "created": 1767726567748, "updated": 1767726567766 },
+ "directory": "/Users/matigreen/dotfiles",
+ "parentID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "summary": { "deletions": 0, "files": 0, "additions": 0 },
+ "id": "ses_46b492ebbffel5oIJ1qUl9GKFh"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "user",
+ "summary": { "title": "Debugging alt-M keybind opencode.nvim", "diffs": [] },
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "tools": {
+ "todoread": false,
+ "task": false,
+ "browser_*": false,
+ "atlassian_*": false,
+ "jira_get": true,
+ "confluence_*": false,
+ "todowrite": false,
+ "playwright": false,
+ "write": true,
+ "edit": true,
+ "bash": true
+ },
+ "time": { "created": 1767726567752 },
+ "id": "msg_b94b6d147001k2DbeF1m2JpIP3",
+ "agent": "nvim",
+ "model": { "providerID": "anthropic", "modelID": "claude-sonnet-4-5" }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "snapshot": "29b76c5b84a59e892d23447cd82abb3afea86e41",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "id": "prt_b94b6de23001y1RTIdtsaHvsAw",
+ "messageID": "msg_b94b6d14b001y9ggcfX7Qmvfb4"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": " the `",
+ "part": {
+ "type": "text",
+ "text": "I'll investigate the `",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "id": "prt_b94b6de240010A9XWmezoH5cz9",
+ "time": { "start": 1767726571044 },
+ "messageID": "msg_b94b6d14b001y9ggcfX7Qmvfb4"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": "code.nvim.",
+ "part": {
+ "type": "text",
+ "text": "I'll investigate the `alt-M` keybind issue for opencode.nvim.",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "id": "prt_b94b6de240010A9XWmezoH5cz9",
+ "time": { "start": 1767726571044 },
+ "messageID": "msg_b94b6d14b001y9ggcfX7Qmvfb4"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": " files",
+ "part": {
+ "type": "text",
+ "text": "I'll investigate the `alt-M` keybind issue for opencode.nvim. Let me start by examining the relevant configuration files",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "id": "prt_b94b6de240010A9XWmezoH5cz9",
+ "time": { "start": 1767726571044 },
+ "messageID": "msg_b94b6d14b001y9ggcfX7Qmvfb4"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "text": "I'll investigate the `alt-M` keybind issue for opencode.nvim. Let me start by examining the relevant configuration files.",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "id": "prt_b94b6de240010A9XWmezoH5cz9",
+ "time": { "start": 1767726571695, "end": 1767726571695 },
+ "messageID": "msg_b94b6d14b001y9ggcfX7Qmvfb4"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "callID": "toolu_01BbJ53KgPXPLXqVbMQhaPyT",
+ "tool": "read",
+ "id": "prt_b94b6e0b3001mCVItg2EJfPAB2",
+ "messageID": "msg_b94b6d14b001y9ggcfX7Qmvfb4",
+ "state": { "input": {}, "raw": "", "status": "pending" }
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "callID": "toolu_017Li9bzxEHcp7pwBxRu4MxU",
+ "tool": "task",
+ "id": "prt_b94b6b5f3001JaaXlpjO9TFn2O",
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb",
+ "state": {
+ "title": "Debug alt-M keybind issue",
+ "metadata": {
+ "summary": [{ "tool": "read", "id": "prt_b94b6e0b3001mCVItg2EJfPAB2", "state": { "status": "pending" } }],
+ "sessionId": "ses_46b492ebbffel5oIJ1qUl9GKFh"
+ },
+ "input": {
+ "subagent_type": "nvim",
+ "prompt": "The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.",
+ "description": "Debug alt-M keybind issue"
+ },
+ "time": { "start": 1767726571700 },
+ "status": "running"
+ }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "callID": "toolu_01BbJ53KgPXPLXqVbMQhaPyT",
+ "tool": "read",
+ "id": "prt_b94b6e0b3001mCVItg2EJfPAB2",
+ "messageID": "msg_b94b6d14b001y9ggcfX7Qmvfb4",
+ "state": {
+ "status": "completed",
+ "output": "\n00001| return {\n00002| \"sudo-tee/opencode.nvim\",\n00003| config = function()\n00004| -- Check if custom configs are enabled\n00005| local custom_enabled = vim.g.opencode_custom_enabled == true\n00006| \n00007| if custom_enabled then\n00008| -- =========================================================================\n00009| -- CUSTOM CONFIGURATION MODE\n00010| -- =========================================================================\n00011| require(\"opencode\").setup({\n00012| default_mode = \"plan\", -- Default to Plan mode instead of Build\n00013| keymap = {\n00014| editor = {\n00015| [\"o\"] = { \"switch_mode\", desc = \"Toggle agent (Plan/Build)\" },\n00016| [\"ou\"] = { \"undo\", desc = \"Undo last message\" },\n00017| [\"o\"] = { \"redo\", desc = \"Redo message\" },\n00018| -- Override default provider switcher with custom favorites\n00019| [\"op\"] = {\n00020| function()\n00021| require(\"gmati.plugins.ai.opencode_favorites\").select_favorite_provider()\n00022| end,\n00023| desc = \"Switch provider (favorites)\",\n00024| },\n00025| },\n00026| input_window = {\n00027| -- Enter submits only in normal mode\n00028| [\"\"] = { \"submit_input_prompt\", mode = \"n\" },\n00029| },\n00030| },\n00031| ui = {\n00032| -- Disable built-in status displays (we use lualine instead)\n00033| display_model = false,\n00034| display_context_size = false,\n00035| display_cost = false,\n00036| },\n00037| debug = {\n00038| capture_streamed_events = true\n00039| }\n00040| })\n00041| \n00042| -- Apply UI patches to customize OpenCode rendering\n00043| vim.defer_fn(function()\n00044| require(\"gmati.plugins.ai.opencode_ui_patches\").apply_all()\n00045| end, 0)\n00046| \n00047| -- Setup custom keymaps (mode switching, diagnostics, emergency)\n00048| require(\"gmati.plugins.ai.opencode_keymaps\").setup()\n00049| \n00050| -- Setup diagnostics monitoring (health checks, error tracking)\n00051| vim.defer_fn(function()\n00052| local ok, diagnostics = pcall(require, \"gmati.plugins.ai.opencode_diagnostics\")\n00053| if ok then\n00054| diagnostics.setup()\n00055| end\n00056| end, 300)\n00057| \n00058| -- Setup LSP/features integration (disable during thinking)\n00059| vim.defer_fn(function()\n00060| local ok, integration = pcall(require, \"gmati.plugins.ai.opencode_integration\")\n00061| if ok then\n00062| integration.setup()\n00063| end\n00064| end, 200)\n00065| \n00066| -- Cleanup on exit\n00067| vim.api.nvim_create_autocmd(\"VimLeavePre\", {\n00068| callback = function()\n00069| local ok, integration = pcall(require, \"gmati.plugins.ai.opencode_integration\")\n00070| if ok then\n00071| integration.cleanup()\n00072| end\n00073| \n00074| local ok_diag, diagnostics = pcall(require, \"gmati.plugins.ai.opencode_diagnostics\")\n00075| if ok_diag then\n00076| diagnostics.cleanup()\n00077| end\n00078| end,\n00079| })\n00080| else\n00081| -- =========================================================================\n00082| -- VANILLA CONFIGURATION MODE\n00083| -- =========================================================================\n00084| require(\"opencode\").setup({\n00085| default_mode = \"plan\", -- Keep your default mode preference\n00086| debug = {\n00087| capture_streamed_events = true\n00088| }\n00089| })\n00090| end\n00091| end,\n00092| dependencies = {\n00093| \"nvim-lua/plenary.nvim\",\n00094| {\n00095| \"MeanderingProgrammer/render-markdown.nvim\",\n00096| opts = {\n00097| anti_conceal = { enabled = false },\n00098| file_types = { \"markdown\", \"opencode_output\" },\n00099| },\n00100| ft = { \"markdown\", \"Avante\", \"copilot-chat\", \"opencode_output\" },\n00101| },\n00102| -- Optional, for file mentions and commands completion\n00103| \"hrsh7th/nvim-cmp\",\n00104| -- Optional, for file mentions picker\n00105| \"folke/snacks.nvim\",\n00106| },\n00107| }\n00108| \n\n(End of file - total 108 lines)\n",
+ "metadata": {
+ "preview": "return {\n \"sudo-tee/opencode.nvim\",\n config = function()\n -- Check if custom configs are enabled\n local custom_enabled = vim.g.opencode_custom_enabled == true\n\n if custom_enabled then\n -- =========================================================================\n -- CUSTOM CONFIGURATION MODE\n -- =========================================================================\n require(\"opencode\").setup({\n default_mode = \"plan\", -- Default to Plan mode instead of Build\n keymap = {\n editor = {\n [\"o\"] = { \"switch_mode\", desc = \"Toggle agent (Plan/Build)\" },\n [\"ou\"] = { \"undo\", desc = \"Undo last message\" },\n [\"o\"] = { \"redo\", desc = \"Redo message\" },\n -- Override default provider switcher with custom favorites\n [\"op\"] = {\n function()"
+ },
+ "input": { "filePath": "/Users/matigreen/dotfiles/nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua" },
+ "time": { "start": 1767726572684, "end": 1767726572708 },
+ "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua"
+ }
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "callID": "toolu_017Li9bzxEHcp7pwBxRu4MxU",
+ "tool": "task",
+ "id": "prt_b94b6b5f3001JaaXlpjO9TFn2O",
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb",
+ "state": {
+ "title": "Debug alt-M keybind issue",
+ "metadata": {
+ "summary": [
+ {
+ "tool": "read",
+ "id": "prt_b94b6e0b3001mCVItg2EJfPAB2",
+ "state": { "status": "completed", "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua" }
+ },
+ { "tool": "read", "id": "prt_b94b6e4a1001n0heEU3dEGxfWa", "state": { "status": "pending" } }
+ ],
+ "sessionId": "ses_46b492ebbffel5oIJ1qUl9GKFh"
+ },
+ "input": {
+ "subagent_type": "nvim",
+ "prompt": "The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.",
+ "description": "Debug alt-M keybind issue"
+ },
+ "time": { "start": 1767726572710 },
+ "status": "running"
+ }
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "callID": "toolu_01NLzNf8fQ5m6CbQmJi61LHi",
+ "tool": "read",
+ "id": "prt_b94b6e4a1001n0heEU3dEGxfWa",
+ "messageID": "msg_b94b6d14b001y9ggcfX7Qmvfb4",
+ "state": { "input": {}, "raw": "", "status": "pending" }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "callID": "toolu_01NLzNf8fQ5m6CbQmJi61LHi",
+ "tool": "read",
+ "id": "prt_b94b6e4a1001n0heEU3dEGxfWa",
+ "messageID": "msg_b94b6d14b001y9ggcfX7Qmvfb4",
+ "state": {
+ "status": "completed",
+ "output": "\n00001| -- OpenCode Keymaps\n00002| -- All custom keybindings for OpenCode functionality\n00003| -- Organized by category for easy discovery and modification\n00004| \n00005| local M = {}\n00006| \n00007| -- Setup all OpenCode keymaps\n00008| function M.setup()\n00009| M.setup_mode_keymaps()\n00010| M.setup_diagnostic_keymaps()\n00011| M.setup_emergency_keymaps()\n00012| end\n00013| \n00014| -- Mode-related keymaps (switching modes, quick build)\n00015| function M.setup_mode_keymaps()\n00016| -- Quick build mode: Switch to build mode and prepare \"build\" command\n00017| vim.keymap.set(\"n\", \"o\", function()\n00018| require(\"gmati.plugins.ai.opencode_build_mode\").quick_build()\n00019| end, { desc = \"Build mode + prepare 'build'\" })\n00020| end\n00021| \n00022| -- Diagnostic keymaps (health status, logs)\n00023| function M.setup_diagnostic_keymaps()\n00024| -- Show OpenCode diagnostics (health status)\n00025| vim.keymap.set(\"n\", \"od\", function()\n00026| local ok, diagnostics = pcall(require, \"gmati.plugins.ai.opencode_diagnostics\")\n00027| if ok then\n00028| diagnostics.show_health_status()\n00029| else\n00030| vim.notify(\"Failed to load OpenCode diagnostics\", vim.log.levels.ERROR)\n00031| end\n00032| end, { desc = \"Show OpenCode diagnostics\" })\n00033| \n00034| -- Open OpenCode server logs\n00035| vim.keymap.set(\"n\", \"oL\", function()\n00036| local ok, diagnostics = pcall(require, \"gmati.plugins.ai.opencode_diagnostics\")\n00037| if ok then\n00038| diagnostics.open_server_logs()\n00039| else\n00040| vim.notify(\"Failed to load OpenCode diagnostics\", vim.log.levels.ERROR)\n00041| end\n00042| end, { desc = \"View OpenCode server logs\" })\n00043| end\n00044| \n00045| -- Emergency keymaps (force stop)\n00046| function M.setup_emergency_keymaps()\n00047| -- Force stop OpenCode: Nuclear option to kill all jobs and reset state\n00048| vim.keymap.set(\"n\", \"oF\", function()\n00049| require(\"gmati.plugins.ai.opencode_force_stop\").force_stop()\n00050| end, { desc = \"Force stop OpenCode (nuclear option)\" })\n00051| end\n00052| \n00053| return M\n00054| \n\n(End of file - total 54 lines)\n",
+ "metadata": {
+ "preview": "-- OpenCode Keymaps\n-- All custom keybindings for OpenCode functionality\n-- Organized by category for easy discovery and modification\n\nlocal M = {}\n\n-- Setup all OpenCode keymaps\nfunction M.setup()\n M.setup_mode_keymaps()\n M.setup_diagnostic_keymaps()\n M.setup_emergency_keymaps()\nend\n\n-- Mode-related keymaps (switching modes, quick build)\nfunction M.setup_mode_keymaps()\n -- Quick build mode: Switch to build mode and prepare \"build\" command\n vim.keymap.set(\"n\", \"o\", function()\n require(\"gmati.plugins.ai.opencode_build_mode\").quick_build()\n end, { desc = \"Build mode + prepare 'build'\" })\nend"
+ },
+ "input": {
+ "filePath": "/Users/matigreen/dotfiles/nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"
+ },
+ "time": { "start": 1767726573388, "end": 1767726573393 },
+ "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"
+ }
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "callID": "toolu_017Li9bzxEHcp7pwBxRu4MxU",
+ "tool": "task",
+ "id": "prt_b94b6b5f3001JaaXlpjO9TFn2O",
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb",
+ "state": {
+ "title": "Debug alt-M keybind issue",
+ "metadata": {
+ "summary": [
+ {
+ "tool": "read",
+ "id": "prt_b94b6e0b3001mCVItg2EJfPAB2",
+ "state": { "status": "completed", "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua" }
+ },
+ {
+ "tool": "read",
+ "id": "prt_b94b6e4a1001n0heEU3dEGxfWa",
+ "state": {
+ "status": "completed",
+ "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"
+ }
+ },
+ { "tool": "read", "id": "prt_b94b6e768001nwQ5wgnzVRZL8B", "state": { "status": "pending" } }
+ ],
+ "sessionId": "ses_46b492ebbffel5oIJ1qUl9GKFh"
+ },
+ "input": {
+ "subagent_type": "nvim",
+ "prompt": "The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.",
+ "description": "Debug alt-M keybind issue"
+ },
+ "time": { "start": 1767726573417 },
+ "status": "running"
+ }
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "callID": "toolu_01SkSniBkbNnBeJr1jwfEvvs",
+ "tool": "read",
+ "id": "prt_b94b6e768001nwQ5wgnzVRZL8B",
+ "messageID": "msg_b94b6d14b001y9ggcfX7Qmvfb4",
+ "state": { "input": {}, "raw": "", "status": "pending" }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "callID": "toolu_01SkSniBkbNnBeJr1jwfEvvs",
+ "tool": "read",
+ "id": "prt_b94b6e768001nwQ5wgnzVRZL8B",
+ "messageID": "msg_b94b6d14b001y9ggcfX7Qmvfb4",
+ "state": {
+ "status": "completed",
+ "output": "\n00001| initial-window = false\n00002| \n00003| quick-terminal-position = center\n00004| quick-terminal-size = 98%,95%\n00005| \n00006| window-padding-x = 16\n00007| window-padding-y = 16\n00008| window-padding-balance = true\n00009| \n00010| theme = catppuccin-mocha.conf\n00011| background-opacity = 0.9\n00012| background-blur-radius = 20\n00013| \n00014| font-family = \"Hack Nerd Font\"\n00015| font-size = 18\n00016| \n00017| # Enable Option key as Alt modifier for terminal keybindings\n00018| macos-option-as-alt = true\n00019| \n00020| keybind = global:cmd+f12=toggle_quick_terminal\n00021| \n00022| keybind = cmd+shift+k=goto_split:top\n00023| keybind = cmd+shift+j=goto_split:bottom\n00024| keybind = cmd+shift+h=goto_split:left\n00025| keybind = cmd+shift+l=goto_split:right\n00026| \n\n(End of file - total 26 lines)\n",
+ "metadata": {
+ "preview": "initial-window = false\n\nquick-terminal-position = center\nquick-terminal-size = 98%,95%\n\nwindow-padding-x = 16\nwindow-padding-y = 16\nwindow-padding-balance = true\n\ntheme = catppuccin-mocha.conf\nbackground-opacity = 0.9\nbackground-blur-radius = 20\n\nfont-family = \"Hack Nerd Font\"\nfont-size = 18\n\n# Enable Option key as Alt modifier for terminal keybindings\nmacos-option-as-alt = true\n\nkeybind = global:cmd+f12=toggle_quick_terminal"
+ },
+ "input": { "filePath": "/Users/matigreen/dotfiles/ghostty/.config/ghostty/config" },
+ "time": { "start": 1767726573681, "end": 1767726573695 },
+ "title": "ghostty/.config/ghostty/config"
+ }
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "callID": "toolu_017Li9bzxEHcp7pwBxRu4MxU",
+ "tool": "task",
+ "id": "prt_b94b6b5f3001JaaXlpjO9TFn2O",
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb",
+ "state": {
+ "title": "Debug alt-M keybind issue",
+ "metadata": {
+ "summary": [
+ {
+ "tool": "read",
+ "id": "prt_b94b6e0b3001mCVItg2EJfPAB2",
+ "state": { "status": "completed", "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua" }
+ },
+ {
+ "tool": "read",
+ "id": "prt_b94b6e4a1001n0heEU3dEGxfWa",
+ "state": {
+ "status": "completed",
+ "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"
+ }
+ },
+ {
+ "tool": "read",
+ "id": "prt_b94b6e768001nwQ5wgnzVRZL8B",
+ "state": { "status": "completed", "title": "ghostty/.config/ghostty/config" }
+ }
+ ],
+ "sessionId": "ses_46b492ebbffel5oIJ1qUl9GKFh"
+ },
+ "input": {
+ "subagent_type": "nvim",
+ "prompt": "The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.",
+ "description": "Debug alt-M keybind issue"
+ },
+ "time": { "start": 1767726573696 },
+ "status": "running"
+ }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "step-finish",
+ "snapshot": "29b76c5b84a59e892d23447cd82abb3afea86e41",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "reason": "tool-calls",
+ "messageID": "msg_b94b6d14b001y9ggcfX7Qmvfb4",
+ "id": "prt_b94b6e910001sHfwoYXshpCwWv",
+ "cost": 0,
+ "tokens": { "reasoning": 0, "input": 2, "output": 235, "cache": { "write": 24673, "read": 0 } }
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "assistant",
+ "finish": "tool-calls",
+ "tokens": { "reasoning": 0, "input": 2, "output": 235, "cache": { "write": 24673, "read": 0 } },
+ "parentID": "msg_b94b6d147001k2DbeF1m2JpIP3",
+ "providerID": "anthropic",
+ "time": { "created": 1767726567755 },
+ "id": "msg_b94b6d14b001y9ggcfX7Qmvfb4",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "modelID": "claude-sonnet-4-5",
+ "mode": "nvim",
+ "cost": 0,
+ "agent": "nvim",
+ "path": { "cwd": "/Users/matigreen/dotfiles", "root": "/Users/matigreen/dotfiles" }
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "assistant",
+ "finish": "tool-calls",
+ "tokens": { "reasoning": 0, "input": 2, "output": 235, "cache": { "write": 24673, "read": 0 } },
+ "parentID": "msg_b94b6d147001k2DbeF1m2JpIP3",
+ "providerID": "anthropic",
+ "time": { "created": 1767726567755, "completed": 1767726573914 },
+ "id": "msg_b94b6d14b001y9ggcfX7Qmvfb4",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "modelID": "claude-sonnet-4-5",
+ "mode": "nvim",
+ "cost": 0,
+ "agent": "nvim",
+ "path": { "cwd": "/Users/matigreen/dotfiles", "root": "/Users/matigreen/dotfiles" }
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "assistant",
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "parentID": "msg_b94b6d147001k2DbeF1m2JpIP3",
+ "providerID": "anthropic",
+ "time": { "created": 1767726573918 },
+ "id": "msg_b94b6e95e001xIoTqqCWgaqBfO",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "modelID": "claude-sonnet-4-5",
+ "mode": "nvim",
+ "cost": 0,
+ "agent": "nvim",
+ "path": { "cwd": "/Users/matigreen/dotfiles", "root": "/Users/matigreen/dotfiles" }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "user",
+ "summary": { "title": "Debugging alt-M keybind opencode.nvim", "diffs": [] },
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "tools": {
+ "todoread": false,
+ "task": false,
+ "browser_*": false,
+ "atlassian_*": false,
+ "jira_get": true,
+ "confluence_*": false,
+ "todowrite": false,
+ "playwright": false,
+ "write": true,
+ "edit": true,
+ "bash": true
+ },
+ "time": { "created": 1767726567752 },
+ "id": "msg_b94b6d147001k2DbeF1m2JpIP3",
+ "agent": "nvim",
+ "model": { "providerID": "anthropic", "modelID": "claude-sonnet-4-5" }
+ }
+ }
+ },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "projectID": "b8136e83cf077521b7177c9660d223a1759f881e",
+ "title": "Debug alt-M keybind issue (@nvim subagent)",
+ "version": "1.0.220",
+ "time": { "created": 1767726567748, "updated": 1767726573935 },
+ "directory": "/Users/matigreen/dotfiles",
+ "parentID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "summary": { "deletions": 0, "files": 0, "additions": 0 },
+ "id": "ses_46b492ebbffel5oIJ1qUl9GKFh"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "snapshot": "29b76c5b84a59e892d23447cd82abb3afea86e41",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "id": "prt_b94b6f600001vrOB25LzH46DAo",
+ "messageID": "msg_b94b6e95e001xIoTqqCWgaqBfO"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": " let",
+ "part": {
+ "type": "text",
+ "text": "Now let",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "id": "prt_b94b6f601001imJME5kdm4mlg6",
+ "time": { "start": 1767726577153 },
+ "messageID": "msg_b94b6e95e001xIoTqqCWgaqBfO"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": "code.",
+ "part": {
+ "type": "text",
+ "text": "Now let me check the opencode.",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "id": "prt_b94b6f601001imJME5kdm4mlg6",
+ "time": { "start": 1767726577153 },
+ "messageID": "msg_b94b6e95e001xIoTqqCWgaqBfO"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": " or",
+ "part": {
+ "type": "text",
+ "text": "Now let me check the opencode.nvim plugin documentation or",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "id": "prt_b94b6f601001imJME5kdm4mlg6",
+ "time": { "start": 1767726577153 },
+ "messageID": "msg_b94b6e95e001xIoTqqCWgaqBfO"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": " default",
+ "part": {
+ "type": "text",
+ "text": "Now let me check the opencode.nvim plugin documentation or source to understand what the default",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "id": "prt_b94b6f601001imJME5kdm4mlg6",
+ "time": { "start": 1767726577153 },
+ "messageID": "msg_b94b6e95e001xIoTqqCWgaqBfO"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": "alt",
+ "part": {
+ "type": "text",
+ "text": "Now let me check the opencode.nvim plugin documentation or source to understand what the default `alt",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "id": "prt_b94b6f601001imJME5kdm4mlg6",
+ "time": { "start": 1767726577153 },
+ "messageID": "msg_b94b6e95e001xIoTqqCWgaqBfO"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": "` ke",
+ "part": {
+ "type": "text",
+ "text": "Now let me check the opencode.nvim plugin documentation or source to understand what the default `alt-M` ke",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "id": "prt_b94b6f601001imJME5kdm4mlg6",
+ "time": { "start": 1767726577153 },
+ "messageID": "msg_b94b6e95e001xIoTqqCWgaqBfO"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "delta": "d does",
+ "part": {
+ "type": "text",
+ "text": "Now let me check the opencode.nvim plugin documentation or source to understand what the default `alt-M` keybind does",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "id": "prt_b94b6f601001imJME5kdm4mlg6",
+ "time": { "start": 1767726577153 },
+ "messageID": "msg_b94b6e95e001xIoTqqCWgaqBfO"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "text": "Now let me check the opencode.nvim plugin documentation or source to understand what the default `alt-M` keybind does:",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "id": "prt_b94b6f601001imJME5kdm4mlg6",
+ "time": { "start": 1767726578336, "end": 1767726578336 },
+ "messageID": "msg_b94b6e95e001xIoTqqCWgaqBfO"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "callID": "toolu_0135HE3hqPJhMmqYtvzz2xyu",
+ "tool": "bash",
+ "id": "prt_b94b6faa0001LKlGQTIabbHKvg",
+ "messageID": "msg_b94b6e95e001xIoTqqCWgaqBfO",
+ "state": { "input": {}, "raw": "", "status": "pending" }
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "callID": "toolu_017Li9bzxEHcp7pwBxRu4MxU",
+ "tool": "task",
+ "id": "prt_b94b6b5f3001JaaXlpjO9TFn2O",
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb",
+ "state": {
+ "title": "Debug alt-M keybind issue",
+ "metadata": {
+ "summary": [
+ {
+ "tool": "read",
+ "id": "prt_b94b6e0b3001mCVItg2EJfPAB2",
+ "state": { "status": "completed", "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua" }
+ },
+ {
+ "tool": "read",
+ "id": "prt_b94b6e4a1001n0heEU3dEGxfWa",
+ "state": {
+ "status": "completed",
+ "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"
+ }
+ },
+ {
+ "tool": "read",
+ "id": "prt_b94b6e768001nwQ5wgnzVRZL8B",
+ "state": { "status": "completed", "title": "ghostty/.config/ghostty/config" }
+ },
+ { "tool": "bash", "id": "prt_b94b6faa0001LKlGQTIabbHKvg", "state": { "status": "pending" } }
+ ],
+ "sessionId": "ses_46b492ebbffel5oIJ1qUl9GKFh"
+ },
+ "input": {
+ "subagent_type": "nvim",
+ "prompt": "The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.",
+ "description": "Debug alt-M keybind issue"
+ },
+ "time": { "start": 1767726578336 },
+ "status": "running"
+ }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "callID": "toolu_0135HE3hqPJhMmqYtvzz2xyu",
+ "tool": "bash",
+ "id": "prt_b94b6faa0001LKlGQTIabbHKvg",
+ "messageID": "msg_b94b6e95e001xIoTqqCWgaqBfO",
+ "state": {
+ "input": {
+ "command": "cd ~/.local/share/nvim/lazy/opencode.nvim && find . -name \"*.lua\" -type f | head -20",
+ "description": "Find opencode.nvim plugin files"
+ },
+ "time": { "start": 1767726579322 },
+ "status": "running"
+ }
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "callID": "toolu_017Li9bzxEHcp7pwBxRu4MxU",
+ "tool": "task",
+ "id": "prt_b94b6b5f3001JaaXlpjO9TFn2O",
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb",
+ "state": {
+ "title": "Debug alt-M keybind issue",
+ "metadata": {
+ "summary": [
+ {
+ "tool": "read",
+ "id": "prt_b94b6e0b3001mCVItg2EJfPAB2",
+ "state": { "status": "completed", "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua" }
+ },
+ {
+ "tool": "read",
+ "id": "prt_b94b6e4a1001n0heEU3dEGxfWa",
+ "state": {
+ "status": "completed",
+ "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"
+ }
+ },
+ {
+ "tool": "read",
+ "id": "prt_b94b6e768001nwQ5wgnzVRZL8B",
+ "state": { "status": "completed", "title": "ghostty/.config/ghostty/config" }
+ },
+ { "tool": "bash", "id": "prt_b94b6faa0001LKlGQTIabbHKvg", "state": { "status": "running" } }
+ ],
+ "sessionId": "ses_46b492ebbffel5oIJ1qUl9GKFh"
+ },
+ "input": {
+ "subagent_type": "nvim",
+ "prompt": "The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.",
+ "description": "Debug alt-M keybind issue"
+ },
+ "time": { "start": 1767726579323 },
+ "status": "running"
+ }
+ }
+ }
+ },
+ {
+ "type": "permission.updated",
+ "properties": {
+ "title": "cd ~/.local/share/nvim/lazy/opencode.nvim && find . -name \"*.lua\" -type f | head -20",
+ "pattern": ["find . *", "head *"],
+ "type": "bash",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "callID": "toolu_0135HE3hqPJhMmqYtvzz2xyu",
+ "metadata": {
+ "command": "cd ~/.local/share/nvim/lazy/opencode.nvim && find . -name \"*.lua\" -type f | head -20",
+ "patterns": ["find . *", "head *"]
+ },
+ "id": "per_b94b6fe95001R3s3aeqFb9wsLe",
+ "time": { "created": 1767726579349 },
+ "messageID": "msg_b94b6e95e001xIoTqqCWgaqBfO"
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "permission.replied",
+ "properties": {
+ "permissionID": "per_b94b6fe95001R3s3aeqFb9wsLe",
+ "response": "once",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh"
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "callID": "toolu_0135HE3hqPJhMmqYtvzz2xyu",
+ "tool": "bash",
+ "id": "prt_b94b6faa0001LKlGQTIabbHKvg",
+ "messageID": "msg_b94b6e95e001xIoTqqCWgaqBfO",
+ "state": {
+ "status": "completed",
+ "output": "./tests/mocks/session_list.lua\n./tests/unit/hooks_spec.lua\n./tests/unit/timer_spec.lua\n./tests/unit/input_window_spec.lua\n./tests/unit/server_job_spec.lua\n./tests/unit/config_spec.lua\n./tests/unit/api_spec.lua\n./tests/unit/event_manager_spec.lua\n./tests/unit/init_spec.lua\n./tests/unit/state_spec.lua\n./tests/unit/image_handler_spec.lua\n./tests/unit/id_spec.lua\n./tests/unit/api_client_spec.lua\n./tests/unit/context_spec.lua\n./tests/unit/session_spec.lua\n./tests/unit/config_file_spec.lua\n./tests/unit/opencode_server_spec.lua\n./tests/unit/core_spec.lua\n./tests/unit/context_completion_spec.lua\n./tests/unit/render_state_spec.lua\n",
+ "metadata": {
+ "exit": 0,
+ "output": "./tests/mocks/session_list.lua\n./tests/unit/hooks_spec.lua\n./tests/unit/timer_spec.lua\n./tests/unit/input_window_spec.lua\n./tests/unit/server_job_spec.lua\n./tests/unit/config_spec.lua\n./tests/unit/api_spec.lua\n./tests/unit/event_manager_spec.lua\n./tests/unit/init_spec.lua\n./tests/unit/state_spec.lua\n./tests/unit/image_handler_spec.lua\n./tests/unit/id_spec.lua\n./tests/unit/api_client_spec.lua\n./tests/unit/context_spec.lua\n./tests/unit/session_spec.lua\n./tests/unit/config_file_spec.lua\n./tests/unit/opencode_server_spec.lua\n./tests/unit/core_spec.lua\n./tests/unit/context_completion_spec.lua\n./tests/unit/render_state_spec.lua\n",
+ "description": "Find opencode.nvim plugin files"
+ },
+ "input": {
+ "command": "cd ~/.local/share/nvim/lazy/opencode.nvim && find . -name \"*.lua\" -type f | head -20",
+ "description": "Find opencode.nvim plugin files"
+ },
+ "time": { "start": 1767726579322, "end": 1767726603966 },
+ "title": "Find opencode.nvim plugin files"
+ }
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "callID": "toolu_017Li9bzxEHcp7pwBxRu4MxU",
+ "tool": "task",
+ "id": "prt_b94b6b5f3001JaaXlpjO9TFn2O",
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb",
+ "state": {
+ "title": "Debug alt-M keybind issue",
+ "metadata": {
+ "summary": [
+ {
+ "tool": "read",
+ "id": "prt_b94b6e0b3001mCVItg2EJfPAB2",
+ "state": { "status": "completed", "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua" }
+ },
+ {
+ "tool": "read",
+ "id": "prt_b94b6e4a1001n0heEU3dEGxfWa",
+ "state": {
+ "status": "completed",
+ "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"
+ }
+ },
+ {
+ "tool": "read",
+ "id": "prt_b94b6e768001nwQ5wgnzVRZL8B",
+ "state": { "status": "completed", "title": "ghostty/.config/ghostty/config" }
+ },
+ {
+ "tool": "bash",
+ "id": "prt_b94b6faa0001LKlGQTIabbHKvg",
+ "state": { "status": "completed", "title": "Find opencode.nvim plugin files" }
+ }
+ ],
+ "sessionId": "ses_46b492ebbffel5oIJ1qUl9GKFh"
+ },
+ "input": {
+ "subagent_type": "nvim",
+ "prompt": "The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.",
+ "description": "Debug alt-M keybind issue"
+ },
+ "time": { "start": 1767726603967 },
+ "status": "running"
+ }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "step-finish",
+ "snapshot": "29b76c5b84a59e892d23447cd82abb3afea86e41",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "reason": "tool-calls",
+ "messageID": "msg_b94b6e95e001xIoTqqCWgaqBfO",
+ "id": "prt_b94b75ec0001Fsf2UjpQApsRHh",
+ "cost": 0,
+ "tokens": { "reasoning": 0, "input": 6, "output": 136, "cache": { "write": 2712, "read": 24673 } }
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "assistant",
+ "finish": "tool-calls",
+ "tokens": { "reasoning": 0, "input": 6, "output": 136, "cache": { "write": 2712, "read": 24673 } },
+ "parentID": "msg_b94b6d147001k2DbeF1m2JpIP3",
+ "providerID": "anthropic",
+ "time": { "created": 1767726573918 },
+ "id": "msg_b94b6e95e001xIoTqqCWgaqBfO",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "modelID": "claude-sonnet-4-5",
+ "mode": "nvim",
+ "cost": 0,
+ "agent": "nvim",
+ "path": { "cwd": "/Users/matigreen/dotfiles", "root": "/Users/matigreen/dotfiles" }
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "assistant",
+ "finish": "tool-calls",
+ "tokens": { "reasoning": 0, "input": 6, "output": 136, "cache": { "write": 2712, "read": 24673 } },
+ "parentID": "msg_b94b6d147001k2DbeF1m2JpIP3",
+ "providerID": "anthropic",
+ "time": { "created": 1767726573918, "completed": 1767726604035 },
+ "id": "msg_b94b6e95e001xIoTqqCWgaqBfO",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "modelID": "claude-sonnet-4-5",
+ "mode": "nvim",
+ "cost": 0,
+ "agent": "nvim",
+ "path": { "cwd": "/Users/matigreen/dotfiles", "root": "/Users/matigreen/dotfiles" }
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "assistant",
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "parentID": "msg_b94b6d147001k2DbeF1m2JpIP3",
+ "providerID": "anthropic",
+ "time": { "created": 1767726604039 },
+ "id": "msg_b94b75f07001FvPfzM3IrqRHw3",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "modelID": "claude-sonnet-4-5",
+ "mode": "nvim",
+ "cost": 0,
+ "agent": "nvim",
+ "path": { "cwd": "/Users/matigreen/dotfiles", "root": "/Users/matigreen/dotfiles" }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "projectID": "b8136e83cf077521b7177c9660d223a1759f881e",
+ "title": "Debug alt-M keybind issue (@nvim subagent)",
+ "version": "1.0.220",
+ "time": { "created": 1767726567748, "updated": 1767726604056 },
+ "directory": "/Users/matigreen/dotfiles",
+ "parentID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "summary": { "deletions": 0, "files": 0, "additions": 0 },
+ "id": "ses_46b492ebbffel5oIJ1qUl9GKFh"
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "role": "user",
+ "summary": { "title": "Debugging alt-M keybind opencode.nvim", "diffs": [] },
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "tools": {
+ "todoread": false,
+ "task": false,
+ "browser_*": false,
+ "atlassian_*": false,
+ "jira_get": true,
+ "confluence_*": false,
+ "todowrite": false,
+ "playwright": false,
+ "write": true,
+ "edit": true,
+ "bash": true
+ },
+ "time": { "created": 1767726567752 },
+ "id": "msg_b94b6d147001k2DbeF1m2JpIP3",
+ "agent": "nvim",
+ "model": { "providerID": "anthropic", "modelID": "claude-sonnet-4-5" }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "snapshot": "29b76c5b84a59e892d23447cd82abb3afea86e41",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "id": "prt_b94b76a1d001uetcdCGKMa7pGM",
+ "messageID": "msg_b94b75f07001FvPfzM3IrqRHw3"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "callID": "toolu_01XNzaXKr6tXjYSfRSikTw7Z",
+ "tool": "bash",
+ "id": "prt_b94b76a20001J4RYEL24y0dMrZ",
+ "messageID": "msg_b94b75f07001FvPfzM3IrqRHw3",
+ "state": { "input": {}, "raw": "", "status": "pending" }
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "callID": "toolu_017Li9bzxEHcp7pwBxRu4MxU",
+ "tool": "task",
+ "id": "prt_b94b6b5f3001JaaXlpjO9TFn2O",
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb",
+ "state": {
+ "title": "Debug alt-M keybind issue",
+ "metadata": {
+ "summary": [
+ {
+ "tool": "read",
+ "id": "prt_b94b6e0b3001mCVItg2EJfPAB2",
+ "state": { "status": "completed", "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua" }
+ },
+ {
+ "tool": "read",
+ "id": "prt_b94b6e4a1001n0heEU3dEGxfWa",
+ "state": {
+ "status": "completed",
+ "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"
+ }
+ },
+ {
+ "tool": "read",
+ "id": "prt_b94b6e768001nwQ5wgnzVRZL8B",
+ "state": { "status": "completed", "title": "ghostty/.config/ghostty/config" }
+ },
+ {
+ "tool": "bash",
+ "id": "prt_b94b6faa0001LKlGQTIabbHKvg",
+ "state": { "status": "completed", "title": "Find opencode.nvim plugin files" }
+ },
+ { "tool": "bash", "id": "prt_b94b76a20001J4RYEL24y0dMrZ", "state": { "status": "pending" } }
+ ],
+ "sessionId": "ses_46b492ebbffel5oIJ1qUl9GKFh"
+ },
+ "input": {
+ "subagent_type": "nvim",
+ "prompt": "The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.",
+ "description": "Debug alt-M keybind issue"
+ },
+ "time": { "start": 1767726606880 },
+ "status": "running"
+ }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "callID": "toolu_01XNzaXKr6tXjYSfRSikTw7Z",
+ "tool": "bash",
+ "id": "prt_b94b76a20001J4RYEL24y0dMrZ",
+ "messageID": "msg_b94b75f07001FvPfzM3IrqRHw3",
+ "state": {
+ "input": {
+ "command": "cd ~/.local/share/nvim/lazy/opencode.nvim && grep -r \"alt-M\\|\" --include=\"*.lua\" | head -20",
+ "description": "Search for alt-M keybind in opencode.nvim"
+ },
+ "time": { "start": 1767726607982 },
+ "status": "running"
+ }
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "sessionID": "ses_46b499f08ffe3aldWmWZoH6N2m",
+ "callID": "toolu_017Li9bzxEHcp7pwBxRu4MxU",
+ "tool": "task",
+ "id": "prt_b94b6b5f3001JaaXlpjO9TFn2O",
+ "messageID": "msg_b94b6948d002pFurK7t7q4bSyb",
+ "state": {
+ "title": "Debug alt-M keybind issue",
+ "metadata": {
+ "summary": [
+ {
+ "tool": "read",
+ "id": "prt_b94b6e0b3001mCVItg2EJfPAB2",
+ "state": { "status": "completed", "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua" }
+ },
+ {
+ "tool": "read",
+ "id": "prt_b94b6e4a1001n0heEU3dEGxfWa",
+ "state": {
+ "status": "completed",
+ "title": "nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua"
+ }
+ },
+ {
+ "tool": "read",
+ "id": "prt_b94b6e768001nwQ5wgnzVRZL8B",
+ "state": { "status": "completed", "title": "ghostty/.config/ghostty/config" }
+ },
+ {
+ "tool": "bash",
+ "id": "prt_b94b6faa0001LKlGQTIabbHKvg",
+ "state": { "status": "completed", "title": "Find opencode.nvim plugin files" }
+ },
+ { "tool": "bash", "id": "prt_b94b76a20001J4RYEL24y0dMrZ", "state": { "status": "running" } }
+ ],
+ "sessionId": "ses_46b492ebbffel5oIJ1qUl9GKFh"
+ },
+ "input": {
+ "subagent_type": "nvim",
+ "prompt": "The user reports that the `alt-M` keybind does not work for the opencode.nvim plugin, even though it's the default keymap of the plugin.\n\nContext:\n- The opencode.nvim plugin is installed at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode.lua`\n- Custom configuration is enabled (`vim.g.opencode_custom_enabled == true`)\n- The setup includes custom keymaps that override some defaults\n- There's a custom keymaps module at `file://nvim/.config/nvim/lua/gmati/plugins/ai/opencode_keymaps.lua`\n\nPlease investigate:\n1. What is the default `alt-M` keybind supposed to do in opencode.nvim?\n2. Check if the custom configuration is overriding or disabling this keybind\n3. Review the `opencode_keymaps.lua` file to see if there are any conflicts\n4. Check if there are any macOS-specific issues with alt/option key bindings in the terminal (Ghostty)\n5. Provide a solution to restore the `alt-M` functionality\n\nReturn your findings and a recommended fix.",
+ "description": "Debug alt-M keybind issue"
+ },
+ "time": { "start": 1767726607982 },
+ "status": "running"
+ }
+ }
+ }
+ },
+ {
+ "type": "permission.updated",
+ "properties": {
+ "title": "cd ~/.local/share/nvim/lazy/opencode.nvim && grep -r \"alt-M\\|\" --include=\"*.lua\" | head -20",
+ "pattern": ["grep \"alt-M\\|\" *", "head *"],
+ "type": "bash",
+ "sessionID": "ses_46b492ebbffel5oIJ1qUl9GKFh",
+ "callID": "toolu_01XNzaXKr6tXjYSfRSikTw7Z",
+ "metadata": {
+ "command": "cd ~/.local/share/nvim/lazy/opencode.nvim && grep -r \"alt-M\\|\" --include=\"*.lua\" | head -20",
+ "patterns": ["grep \"alt-M\\|\" *", "head *"]
+ },
+ "id": "per_b94b76e73001ml5seBvInCYYHG",
+ "time": { "created": 1767726607987 },
+ "messageID": "msg_b94b75f07001FvPfzM3IrqRHw3"
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] }
+]
diff --git a/tests/data/planning.expected.json b/tests/data/planning.expected.json
index 00239ea6..63300cef 100644
--- a/tests/data/planning.expected.json
+++ b/tests/data/planning.expected.json
@@ -1 +1,527 @@
-{"extmarks":[[1,1,0,{"right_gravity":true,"ns_id":3,"priority":10,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-11 17:41:45)","OpencodeHint"],[" [msg_9d45d40c9001s7A1sP3Ew537QN]","OpencodeHint"]],"virt_text_hide":false,"virt_text_win_col":-3}],[2,2,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_hide":false,"virt_text_win_col":-3}],[3,3,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_hide":false,"virt_text_win_col":-3}],[4,4,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_hide":false,"virt_text_win_col":-3}],[5,5,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_hide":false,"virt_text_win_col":-3}],[6,8,0,{"right_gravity":true,"ns_id":3,"priority":10,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["PLAN","OpencodeMessageRoleAssistant"],[" claude-sonnet-4","OpencodeHint"],[" (2025-10-11 17:41:45)","OpencodeHint"],[" [msg_9d45d411b00254Lm5jVRwAeQxT]","OpencodeHint"]],"virt_text_hide":false,"virt_text_win_col":-3}],[7,12,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_hide":false,"virt_text_win_col":-1}],[8,13,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_hide":false,"virt_text_win_col":-1}],[9,14,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_hide":false,"virt_text_win_col":-1}],[10,15,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_hide":false,"virt_text_win_col":-1}],[11,16,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_hide":false,"virt_text_win_col":-1}],[12,19,0,{"right_gravity":true,"ns_id":3,"priority":10,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["PLAN","OpencodeMessageRoleAssistant"],[" claude-sonnet-4","OpencodeHint"],[" (2025-10-11 17:41:51)","OpencodeHint"],[" [msg_9d45d585800269UgJnOLD8i2pF]","OpencodeHint"]],"virt_text_hide":false,"virt_text_win_col":-3}],[13,24,0,{"right_gravity":true,"ns_id":3,"priority":10,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["PLAN","OpencodeMessageRoleAssistant"],[" claude-sonnet-4","OpencodeHint"],[" (2025-10-11 17:41:54)","OpencodeHint"],[" [msg_9d45d65b40026mDvwR5cCGTA30]","OpencodeHint"]],"virt_text_hide":false,"virt_text_win_col":-3}],[14,26,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_hide":false,"virt_text_win_col":-1}],[15,27,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_hide":false,"virt_text_win_col":-1}],[16,28,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_hide":false,"virt_text_win_col":-1}],[17,29,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_hide":false,"virt_text_win_col":-1}],[18,30,0,{"right_gravity":true,"ns_id":3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_hide":false,"virt_text_win_col":-1}],[19,33,0,{"right_gravity":true,"ns_id":3,"priority":10,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["PLAN","OpencodeMessageRoleAssistant"],[" claude-sonnet-4","OpencodeHint"],[" (2025-10-11 17:41:58)","OpencodeHint"],[" [msg_9d45d7390002yE2ve5szXtMdw0]","OpencodeHint"]],"virt_text_hide":false,"virt_text_win_col":-3}]],"timestamp":1769172200,"actions":[],"lines":["----","","","can you make a new neovim plugin for me?","","[`a-empty.txt`](a-empty.txt)","","----","","","I'll help you create a new Neovim plugin. Let me first examine your current setup and then create the plugin structure.","","** plan** `4 todos`","- [ ] Examine existing Lua plugin structure ","- [ ] Create basic plugin directory structure ","- [ ] Write main plugin init.lua file ","- [ ] Create plugin documentation ","","----","","","** read** `/Users/cam/tmp/a/lua/example-plugin/init.lua`","","----","","","** plan** `3 todos`","- [x] Examine existing Lua plugin structure ","- [-] Create basic plugin directory structure ","- [ ] Write main plugin init.lua file ","- [ ] Create plugin documentation ","","----","","","What would you like your Neovim plugin to do? I can see you have an example plugin structure already. I'll need to know:","","1. What functionality you want the plugin to provide","2. What you'd like to name it","3. Any specific features or commands you want to include","","Once you provide these details, I can create a complete plugin structure for you based on the pattern I see in your existing example-plugin.","",""]}
+{
+ "actions": [],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-11 17:41:45)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9d45d40c9001s7A1sP3Ew537QN]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 2,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 3,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 4,
+ 4,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 5,
+ 5,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 6,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "PLAN",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " claude-sonnet-4",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-11 17:41:45)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9d45d411b00254Lm5jVRwAeQxT]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 7,
+ 12,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 8,
+ 13,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 9,
+ 14,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 10,
+ 15,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 11,
+ 16,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 12,
+ 19,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "PLAN",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " claude-sonnet-4",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-11 17:41:51)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9d45d585800269UgJnOLD8i2pF]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 13,
+ 24,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "PLAN",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " claude-sonnet-4",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-11 17:41:54)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9d45d65b40026mDvwR5cCGTA30]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 14,
+ 26,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 15,
+ 27,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 16,
+ 28,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 17,
+ 29,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 18,
+ 30,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 19,
+ 33,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "PLAN",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " claude-sonnet-4",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-11 17:41:58)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9d45d7390002yE2ve5szXtMdw0]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "can you make a new neovim plugin for me?",
+ "",
+ "[`a-empty.txt`](a-empty.txt)",
+ "",
+ "----",
+ "",
+ "",
+ "I'll help you create a new Neovim plugin. Let me first examine your current setup and then create the plugin structure.",
+ "",
+ "** plan** `4 todos`",
+ "- [ ] Examine existing Lua plugin structure ",
+ "- [ ] Create basic plugin directory structure ",
+ "- [ ] Write main plugin init.lua file ",
+ "- [ ] Create plugin documentation ",
+ "",
+ "----",
+ "",
+ "",
+ "** read** `/Users/cam/tmp/a/lua/example-plugin/init.lua`",
+ "",
+ "----",
+ "",
+ "",
+ "** plan** `3 todos`",
+ "- [x] Examine existing Lua plugin structure ",
+ "- [-] Create basic plugin directory structure ",
+ "- [ ] Write main plugin init.lua file ",
+ "- [ ] Create plugin documentation ",
+ "",
+ "----",
+ "",
+ "",
+ "What would you like your Neovim plugin to do? I can see you have an example plugin structure already. I'll need to know:",
+ "",
+ "1. What functionality you want the plugin to provide",
+ "2. What you'd like to name it",
+ "3. Any specific features or commands you want to include",
+ "",
+ "Once you provide these details, I can create a complete plugin structure for you based on the pattern I see in your existing example-plugin.",
+ "",
+ ""
+ ],
+ "timestamp": 1770748578
+}
\ No newline at end of file
diff --git a/tests/data/question-ask-replied.expected.json b/tests/data/question-ask-replied.expected.json
index db08b5a5..2b615069 100644
--- a/tests/data/question-ask-replied.expected.json
+++ b/tests/data/question-ask-replied.expected.json
@@ -1 +1,326 @@
-{"extmarks":[[1,1,0,{"priority":10,"virt_text_pos":"win_col","virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2026-01-26 14:23:12)","OpencodeHint"],[" [msg_bfaafef41001700DjtCwvhFxse]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"right_gravity":true,"virt_text_repeat_linebreak":false}],[2,2,0,{"priority":4096,"virt_text_pos":"win_col","virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"right_gravity":true,"virt_text_repeat_linebreak":true}],[3,3,0,{"priority":4096,"virt_text_pos":"win_col","virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"right_gravity":true,"virt_text_repeat_linebreak":true}],[4,4,0,{"priority":4096,"virt_text_pos":"win_col","virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"right_gravity":true,"virt_text_repeat_linebreak":true}],[5,5,0,{"priority":4096,"virt_text_pos":"win_col","virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"right_gravity":true,"virt_text_repeat_linebreak":true}],[6,6,0,{"priority":4096,"virt_text_pos":"win_col","virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"right_gravity":true,"virt_text_repeat_linebreak":true}],[7,8,0,{"priority":10,"virt_text_pos":"win_col","virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2026-01-26 14:23:12)","OpencodeHint"],[" [msg_bfaafefb3001iBSmqfzFffDjCS]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"right_gravity":true,"virt_text_repeat_linebreak":false}],[8,10,0,{"priority":4096,"virt_text_pos":"win_col","virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"right_gravity":true,"virt_text_repeat_linebreak":true}],[9,11,0,{"priority":4096,"virt_text_pos":"win_col","virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"right_gravity":true,"virt_text_repeat_linebreak":true}],[10,12,0,{"priority":4096,"virt_text_pos":"win_col","virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"right_gravity":true,"virt_text_repeat_linebreak":true}],[11,13,0,{"priority":4096,"virt_text_pos":"win_col","virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"right_gravity":true,"virt_text_repeat_linebreak":true}],[12,16,0,{"priority":10,"virt_text_pos":"win_col","virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2026-01-26 14:23:22)","OpencodeHint"],[" [msg_bfab0156d001NyMxaTnj6Cml0c]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"right_gravity":true,"virt_text_repeat_linebreak":false}]],"timestamp":1769437626,"lines":["----","","","[`tests/replay/renderer_spec.lua`](tests/replay/renderer_spec.lua)","","can you use the question tool and ask me a question with an other choice","","----","","","** question** ","","**Q1:** What is your favorite color?","**A1:** Red","","----","","","Thank you! You chose \"Red\" as your favorite color. If you have a specific task, question, or want to see this preference used in an example or feature, please let me know how you'd like to proceed!","",""],"actions":[]}
+{
+ "actions": [],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2026-01-26 14:23:12)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_bfaafef41001700DjtCwvhFxse]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 2,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 3,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 4,
+ 4,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 5,
+ 5,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 6,
+ 6,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 7,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-4.1",
+ "OpencodeHint"
+ ],
+ [
+ " (2026-01-26 14:23:12)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_bfaafefb3001iBSmqfzFffDjCS]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 8,
+ 10,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 9,
+ 11,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 10,
+ 12,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 11,
+ 13,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 12,
+ 16,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-4.1",
+ "OpencodeHint"
+ ],
+ [
+ " (2026-01-26 14:23:22)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_bfab0156d001NyMxaTnj6Cml0c]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "[`tests/replay/renderer_spec.lua`](tests/replay/renderer_spec.lua)",
+ "",
+ "can you use the question tool and ask me a question with an other choice",
+ "",
+ "----",
+ "",
+ "",
+ "** question** ",
+ "",
+ "**Q1:** What is your favorite color?",
+ "**A1:** Red",
+ "",
+ "----",
+ "",
+ "",
+ "Thank you! You chose \"Red\" as your favorite color. If you have a specific task, question, or want to see this preference used in an example or feature, please let me know how you'd like to proceed!",
+ "",
+ ""
+ ],
+ "timestamp": 1770748578
+}
\ No newline at end of file
diff --git a/tests/data/question-ask-replied.json b/tests/data/question-ask-replied.json
index b9276f67..a87bd319 100644
--- a/tests/data/question-ask-replied.json
+++ b/tests/data/question-ask-replied.json
@@ -1 +1,684 @@
-[{"type":"session.updated","properties":{"info":{"time":{"created":1769437382680,"updated":1769437382680},"title":"New session - 2026-01-26T14:23:02.680Z","version":"1.1.31","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","slug":"sunny-planet","id":"ses_4055037e7ffe7iiIdzWGnWwd0H","directory":"/home/francis/Projects/_nvim/opencode.nvim"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"time":{"created":1769437392705},"role":"user","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"msg_bfaafef41001700DjtCwvhFxse","agent":"build"}}},{"type":"message.part.updated","properties":{"part":{"type":"text","synthetic":true,"text":"Called the Read tool with the following input: {\"filePath\":\"/home/francis/Projects/_nvim/opencode.nvim/tests/replay/renderer_spec.lua\"}","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfaafef42002jckWu6xA2ZV3zg","messageID":"msg_bfaafef41001700DjtCwvhFxse"}}},{"type":"message.part.updated","properties":{"part":{"type":"text","synthetic":true,"text":"\n00001| local state = require('opencode.state')\n00002| local ui = require('opencode.ui.ui')\n00003| local helpers = require('tests.helpers')\n00004| local output_window = require('opencode.ui.output_window')\n00005| local assert = require('luassert')\n00006| local config = require('opencode.config')\n00007| \n00008| local function assert_output_matches(expected, actual, name)\n00009| local normalized_extmarks = helpers.normalize_namespace_ids(actual.extmarks)\n00010| \n00011| assert.are.equal(\n00012| #expected.lines,\n00013| #actual.lines,\n00014| string.format(\n00015| 'Line count mismatch: expected %d, got %d.\\nFirst difference at index %d:\\n Expected: %s\\n Actual: %s',\n00016| #expected.lines,\n00017| #actual.lines,\n00018| math.min(#expected.lines, #actual.lines) + 1,\n00019| vim.inspect(expected.lines[math.min(#expected.lines, #actual.lines) + 1]),\n00020| vim.inspect(actual.lines[math.min(#expected.lines, #actual.lines) + 1])\n00021| )\n00022| )\n00023| \n00024| for i = 1, #expected.lines do\n00025| assert.are.equal(\n00026| expected.lines[i],\n00027| actual.lines[i],\n00028| string.format(\n00029| 'Line %d mismatch:\\n Expected: %s\\n Actual: %s',\n00030| i,\n00031| vim.inspect(expected.lines[i]),\n00032| vim.inspect(actual.lines[i])\n00033| )\n00034| )\n00035| end\n00036| \n00037| assert.are.equal(\n00038| #expected.extmarks,\n00039| #normalized_extmarks,\n00040| string.format(\n00041| 'Extmark count mismatch: expected %d, got %d.\\nFirst difference at index %d:\\n Expected: %s\\n Actual: %s',\n00042| #expected.extmarks,\n00043| #normalized_extmarks,\n00044| math.min(#expected.extmarks, #normalized_extmarks) + 1,\n00045| vim.inspect(expected.extmarks[math.min(#expected.extmarks, #normalized_extmarks) + 1]),\n00046| vim.inspect(normalized_extmarks[math.min(#expected.extmarks, #normalized_extmarks) + 1])\n00047| )\n00048| )\n00049| \n00050| for i = 1, #expected.extmarks do\n00051| assert.are.same(\n00052| expected.extmarks[i],\n00053| normalized_extmarks[i],\n00054| string.format(\n00055| 'Extmark %d mismatch:\\n Expected: %s\\n Actual: %s',\n00056| i,\n00057| vim.inspect(expected.extmarks[i]),\n00058| vim.inspect(normalized_extmarks[i])\n00059| )\n00060| )\n00061| end\n00062| \n00063| local expected_action_count = expected.actions and #expected.actions or 0\n00064| local actual_action_count = actual.actions and #actual.actions or 0\n00065| \n00066| assert.are.equal(\n00067| expected_action_count,\n00068| actual_action_count,\n00069| string.format('Action count mismatch: expected %d, got %d', expected_action_count, actual_action_count)\n00070| )\n00071| \n00072| if expected.actions then\n00073| -- Sort both arrays for consistent comparison since order doesn't matter\n00074| local function sort_actions(actions)\n00075| local sorted = vim.deepcopy(actions)\n00076| table.sort(sorted, function(a, b)\n00077| return vim.inspect(a) < vim.inspect(b)\n00078| end)\n00079| return sorted\n00080| end\n00081| \n00082| assert.same(\n00083| sort_actions(expected.actions),\n00084| sort_actions(actual.actions),\n00085| string.format(\n00086| 'Actions mismatch:\\n Expected: %s\\n Actual: %s',\n00087| vim.inspect(expected.actions),\n00088| vim.inspect(actual.actions)\n00089| )\n00090| )\n00091| end\n00092| end\n00093| \n00094| describe('renderer unit tests', function()\n00095| local event_subscriptions = {\n00096| 'session.updated',\n00097| 'session.compacted',\n00098| 'session.error',\n00099| 'message.updated',\n00100| 'message.removed',\n00101| 'message.part.updated',\n00102| 'message.part.removed',\n00103| 'permission.updated',\n00104| 'permission.replied',\n00105| 'question.replied',\n00106| 'question.asked',\n00107| 'file.edited',\n00108| 'custom.restore_point.created',\n00109| 'custom.emit_events.finished',\n00110| }\n00111| \n00112| before_each(function()\n00113| require('opencode.event_manager').setup()\n00114| end)\n00115| \n00116| it('subsribes to events correctly', function()\n00117| local renderer = require('opencode.ui.renderer')\n00118| local event_manager = state.event_manager\n00119| \n00120| event_manager.events = {}\n00121| \n00122| renderer.setup_subscriptions()\n00123| \n00124| for _, event_name in ipairs(event_subscriptions) do\n00125| assert.is_true(\n00126| event_manager.events[event_name] ~= nil,\n00127| string.format('Renderer did not subscribe to event: %s', event_name)\n00128| )\n00129| end\n00130| end)\n00131| \n00132| it('unsubsribes from events correctly', function()\n00133| local renderer = require('opencode.ui.renderer')\n00134| local event_manager = state.event_manager\n00135| \n00136| renderer.setup_subscriptions()\n00137| \n00138| renderer.setup_subscriptions(false)\n00139| \n00140| for _, event_name in ipairs(event_subscriptions) do\n00141| assert.is_true(\n00142| vim.tbl_isempty(event_manager.events[event_name]),\n00143| string.format('Renderer did not unsubscribe from event: %s', event_name)\n00144| )\n00145| end\n00146| end)\n00147| end)\n00148| \n00149| describe('renderer functional tests', function()\n00150| config.debug.show_ids = true\n00151| \n00152| before_each(function()\n00153| helpers.replay_setup()\n00154| end)\n00155| \n00156| after_each(function()\n00157| if state.windows then\n00158| ui.close_windows(state.windows)\n00159| end\n00160| end)\n00161| \n00162| local json_files = vim.fn.glob('tests/data/*.json', false, true)\n00163| \n00164| -- Don't do the full session test on these files, usually\n00165| -- because they involve permission prompts\n00166| local skip_full_session = {\n00167| 'permission-prompt',\n00168| 'permission-ask-new',\n00169| 'question-ask',\n00170| 'shifting-and-multiple-perms',\n00171| 'message-removal',\n00172| }\n00173| \n00174| for _, filepath in ipairs(json_files) do\n00175| local name = vim.fn.fnamemodify(filepath, ':t:r')\n00176| \n00177| if not name:match('%.expected$') then\n00178| local expected_path = 'tests/data/' .. name .. '.expected.json'\n00179| \n00180| if vim.fn.filereadable(expected_path) == 1 then\n00181| for i = 1, 2 do\n00182| config.ui.output.rendering.event_collapsing = i == 1 and true or false\n00183| it(\n00184| 'replays '\n00185| .. name\n00186| .. ' correctly (event-by-event, '\n00187| .. (config.ui.output.rendering.event_collapsing and 'collapsing' or 'no collapsing')\n00188| .. ')',\n00189| function()\n00190| local events = helpers.load_test_data(filepath)\n00191| state.active_session = helpers.get_session_from_events(events)\n00192| local expected = helpers.load_test_data(expected_path)\n00193| \n00194| helpers.replay_events(events)\n00195| vim.wait(1000, function()\n00196| return vim.tbl_isempty(state.event_manager.throttling_emitter.queue)\n00197| end)\n00198| \n00199| local actual = helpers.capture_output(state.windows and state.windows.output_buf, output_window.namespace)\n00200| assert_output_matches(expected, actual, name)\n00201| end\n00202| )\n00203| end\n00204| \n00205| if not vim.tbl_contains(skip_full_session, name) then\n00206| it('replays ' .. name .. ' correctly (session)', function()\n00207| local renderer = require('opencode.ui.renderer')\n00208| local events = helpers.load_test_data(filepath)\n00209| state.active_session = helpers.get_session_from_events(events, true)\n00210| local expected = helpers.load_test_data(expected_path)\n00211| \n00212| local session_data = helpers.load_session_from_events(events)\n00213| renderer._render_full_session_data(session_data)\n00214| \n00215| local actual = helpers.capture_output(state.windows and state.windows.output_buf, output_window.namespace)\n00216| assert_output_matches(expected, actual, name)\n00217| end)\n00218| end\n00219| end\n00220| end\n00221| end\n00222| end)\n00223| \n\n(End of file - total 223 lines)\n","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfaafef47001HR3fZ3Ct7nScuT","messageID":"msg_bfaafef41001700DjtCwvhFxse"}}},{"type":"message.part.updated","properties":{"part":{"type":"file","messageID":"msg_bfaafef41001700DjtCwvhFxse","url":"file:///home/francis/Projects/_nvim/opencode.nvim/tests/replay/renderer_spec.lua","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","filename":"tests/replay/renderer_spec.lua","id":"prt_bfaafef47002OES5db7H5px77j","mime":"text/plain"}}},{"type":"message.part.updated","properties":{"part":{"type":"text","text":"can you use the question tool and ask me a question with an other choice","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfaafef42001XawiVVGpNU0t5E","messageID":"msg_bfaafef41001700DjtCwvhFxse"}}},{"type":"session.updated","properties":{"info":{"time":{"created":1769437382680,"updated":1769437392735},"title":"New session - 2026-01-26T14:23:02.680Z","version":"1.1.31","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","slug":"sunny-planet","id":"ses_4055037e7ffe7iiIdzWGnWwd0H","directory":"/home/francis/Projects/_nvim/opencode.nvim"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"time":{"created":1769437392819},"modelID":"gpt-4.1","providerID":"github-copilot","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","mode":"build","cost":0,"role":"assistant","tokens":{"input":0,"output":0,"reasoning":0,"cache":{"read":0,"write":0}},"path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_bfaafef41001700DjtCwvhFxse","id":"msg_bfaafefb3001iBSmqfzFffDjCS","agent":"build"}}},{"type":"message.updated","properties":{"info":{"model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"time":{"created":1769437392705},"role":"user","summary":{"diffs":[]},"sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"msg_bfaafef41001700DjtCwvhFxse","agent":"build"}}},{"type":"session.updated","properties":{"info":{"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","time":{"created":1769437382680,"updated":1769437392883},"title":"New session - 2026-01-26T14:23:02.680Z","version":"1.1.31","directory":"/home/francis/Projects/_nvim/opencode.nvim","slug":"sunny-planet","id":"ses_4055037e7ffe7iiIdzWGnWwd0H","summary":{"deletions":0,"additions":0,"files":0}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"step-start","snapshot":"617ad65111b912d010a8ea89957a9c5986bc54f0","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfaaff532001RIiCvjxiMht1EK","messageID":"msg_bfaafefb3001iBSmqfzFffDjCS"}}},{"type":"message.part.updated","properties":{"part":{"type":"tool","callID":"call_b4hwTxyb1alO8r2uMlxeB873","tool":"question","state":{"status":"pending","raw":"","input":{}},"sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfaaff539001jCeh626xIXgw9u","messageID":"msg_bfaafefb3001iBSmqfzFffDjCS"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"question.asked","properties":{"questions":[{"question":"What is your favorite color?","header":"Choose your preferred color","options":[{"description":"A bold, vibrant choice for those who like attention.","label":"Red"},{"description":"A calm, reliable color suitable for most environments.","label":"Blue"},{"description":"Symbolizes growth, harmony, and renewal.","label":"Green"},{"description":"Type your own favorite color.","label":"Other"}]}],"sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","tool":{"messageID":"msg_bfaafefb3001iBSmqfzFffDjCS","callID":"call_b4hwTxyb1alO8r2uMlxeB873"},"id":"que_bfaaff9cc001DnGuMPilJYG9ya"}},{"type":"message.part.updated","properties":{"part":{"type":"tool","callID":"call_b4hwTxyb1alO8r2uMlxeB873","tool":"question","state":{"status":"running","time":{"start":1769437395404},"input":{"questions":[{"question":"What is your favorite color?","header":"Choose your preferred color","options":[{"description":"A bold, vibrant choice for those who like attention.","label":"Red"},{"description":"A calm, reliable color suitable for most environments.","label":"Blue"},{"description":"Symbolizes growth, harmony, and renewal.","label":"Green"},{"description":"Type your own favorite color.","label":"Other"}]}]}},"sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfaaff539001jCeh626xIXgw9u","messageID":"msg_bfaafefb3001iBSmqfzFffDjCS"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"time":{"created":1769437392705},"role":"user","summary":{"title":"Question with Other choice","diffs":[]},"sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"msg_bfaafef41001700DjtCwvhFxse","agent":"build"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"question.replied","properties":{"answers":[["Red"]],"sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","requestID":"que_bfaaff9cc001DnGuMPilJYG9ya"}},{"type":"message.part.updated","properties":{"part":{"type":"tool","callID":"call_b4hwTxyb1alO8r2uMlxeB873","tool":"question","state":{"metadata":{"answers":[["Red"]],"truncated":false},"time":{"start":1769437395404,"end":1769437402416},"title":"Asked 1 question","status":"completed","output":"User has answered your questions: \"What is your favorite color?\"=\"Red\". You can now continue with the user's answers in mind.","input":{"questions":[{"question":"What is your favorite color?","header":"Choose your preferred color","options":[{"description":"A bold, vibrant choice for those who like attention.","label":"Red"},{"description":"A calm, reliable color suitable for most environments.","label":"Blue"},{"description":"Symbolizes growth, harmony, and renewal.","label":"Green"},{"description":"Type your own favorite color.","label":"Other"}]}]}},"sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfaaff539001jCeh626xIXgw9u","messageID":"msg_bfaafefb3001iBSmqfzFffDjCS"}}},{"type":"message.part.updated","properties":{"part":{"type":"step-finish","tokens":{"input":12775,"output":150,"reasoning":0,"cache":{"read":0,"write":0}},"cost":0,"reason":"tool-calls","snapshot":"617ad65111b912d010a8ea89957a9c5986bc54f0","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfab01535001wSIZq9GBd5DM3p","messageID":"msg_bfaafefb3001iBSmqfzFffDjCS"}}},{"type":"message.updated","properties":{"info":{"time":{"created":1769437392819},"modelID":"gpt-4.1","providerID":"github-copilot","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","tokens":{"input":12775,"output":150,"reasoning":0,"cache":{"read":0,"write":0}},"mode":"build","id":"msg_bfaafefb3001iBSmqfzFffDjCS","role":"assistant","cost":0,"path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_bfaafef41001700DjtCwvhFxse","finish":"tool-calls","agent":"build"}}},{"type":"message.updated","properties":{"info":{"time":{"created":1769437392819,"completed":1769437402460},"modelID":"gpt-4.1","providerID":"github-copilot","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","tokens":{"input":12775,"output":150,"reasoning":0,"cache":{"read":0,"write":0}},"mode":"build","id":"msg_bfaafefb3001iBSmqfzFffDjCS","role":"assistant","cost":0,"path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_bfaafef41001700DjtCwvhFxse","finish":"tool-calls","agent":"build"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"time":{"created":1769437402477},"modelID":"gpt-4.1","providerID":"github-copilot","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","mode":"build","cost":0,"role":"assistant","tokens":{"input":0,"output":0,"reasoning":0,"cache":{"read":0,"write":0}},"path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_bfaafef41001700DjtCwvhFxse","id":"msg_bfab0156d001NyMxaTnj6Cml0c","agent":"build"}}},{"type":"message.updated","properties":{"info":{"model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"time":{"created":1769437392705},"role":"user","summary":{"title":"Question with Other choice","diffs":[]},"sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"msg_bfaafef41001700DjtCwvhFxse","agent":"build"}}},{"type":"session.updated","properties":{"info":{"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","time":{"created":1769437382680,"updated":1769437402502},"title":"New session - 2026-01-26T14:23:02.680Z","version":"1.1.31","directory":"/home/francis/Projects/_nvim/opencode.nvim","slug":"sunny-planet","id":"ses_4055037e7ffe7iiIdzWGnWwd0H","summary":{"deletions":0,"additions":0,"files":0}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"step-start","snapshot":"617ad65111b912d010a8ea89957a9c5986bc54f0","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfab01cd9001JINkAnbcXksgNO","messageID":"msg_bfab0156d001NyMxaTnj6Cml0c"}}},{"type":"message.part.updated","properties":{"part":{"type":"text","time":{"start":1769437404381},"text":"Thank you","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfab01cdd001Y6UnA89vh364ZV","messageID":"msg_bfab0156d001NyMxaTnj6Cml0c"},"delta":" you"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","time":{"start":1769437404381},"text":"Thank you! You chose \"Red\" as your favorite color","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfab01cdd001Y6UnA89vh364ZV","messageID":"msg_bfab0156d001NyMxaTnj6Cml0c"},"delta":" color"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","time":{"start":1769437404381},"text":"Thank you! You chose \"Red\" as your favorite color. If you have a specific task, question,","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfab01cdd001Y6UnA89vh364ZV","messageID":"msg_bfab0156d001NyMxaTnj6Cml0c"},"delta":","}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","time":{"start":1769437404381},"text":"Thank you! You chose \"Red\" as your favorite color. If you have a specific task, question, or want to see this preference used in an example","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfab01cdd001Y6UnA89vh364ZV","messageID":"msg_bfab0156d001NyMxaTnj6Cml0c"},"delta":" example"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","time":{"start":1769437404381},"text":"Thank you! You chose \"Red\" as your favorite color. If you have a specific task, question, or want to see this preference used in an example or feature, please let me know how you'd like","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfab01cdd001Y6UnA89vh364ZV","messageID":"msg_bfab0156d001NyMxaTnj6Cml0c"},"delta":" like"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","time":{"start":1769437404381},"text":"Thank you! You chose \"Red\" as your favorite color. If you have a specific task, question, or want to see this preference used in an example or feature, please let me know how you'd like to proceed","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfab01cdd001Y6UnA89vh364ZV","messageID":"msg_bfab0156d001NyMxaTnj6Cml0c"},"delta":" proceed"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","time":{"start":1769437404381},"text":"Thank you! You chose \"Red\" as your favorite color. If you have a specific task, question, or want to see this preference used in an example or feature, please let me know how you'd like to proceed!","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfab01cdd001Y6UnA89vh364ZV","messageID":"msg_bfab0156d001NyMxaTnj6Cml0c"},"delta":"!"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","time":{"start":1769437405694,"end":1769437405694},"text":"Thank you! You chose \"Red\" as your favorite color. If you have a specific task, question, or want to see this preference used in an example or feature, please let me know how you'd like to proceed!","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfab01cdd001Y6UnA89vh364ZV","messageID":"msg_bfab0156d001NyMxaTnj6Cml0c"}}},{"type":"message.part.updated","properties":{"part":{"type":"step-finish","tokens":{"input":874,"output":47,"reasoning":0,"cache":{"read":12032,"write":0}},"cost":0,"reason":"stop","snapshot":"617ad65111b912d010a8ea89957a9c5986bc54f0","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"prt_bfab021ff001EzP7TpA5rv7aTl","messageID":"msg_bfab0156d001NyMxaTnj6Cml0c"}}},{"type":"message.updated","properties":{"info":{"time":{"created":1769437402477},"modelID":"gpt-4.1","providerID":"github-copilot","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","tokens":{"input":874,"output":47,"reasoning":0,"cache":{"read":12032,"write":0}},"mode":"build","id":"msg_bfab0156d001NyMxaTnj6Cml0c","role":"assistant","cost":0,"path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_bfaafef41001700DjtCwvhFxse","finish":"stop","agent":"build"}}},{"type":"message.updated","properties":{"info":{"time":{"created":1769437402477,"completed":1769437405729},"modelID":"gpt-4.1","providerID":"github-copilot","sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","tokens":{"input":874,"output":47,"reasoning":0,"cache":{"read":12032,"write":0}},"mode":"build","id":"msg_bfab0156d001NyMxaTnj6Cml0c","role":"assistant","cost":0,"path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_bfaafef41001700DjtCwvhFxse","finish":"stop","agent":"build"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"model":{"providerID":"github-copilot","modelID":"gpt-4.1"},"time":{"created":1769437392705},"role":"user","summary":{"title":"Question with Other choice","diffs":[]},"sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H","id":"msg_bfaafef41001700DjtCwvhFxse","agent":"build"}}},{"type":"session.idle","properties":{"sessionID":"ses_4055037e7ffe7iiIdzWGnWwd0H"}},{"type":"session.updated","properties":{"info":{"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","time":{"created":1769437382680,"updated":1769437405755},"title":"New session - 2026-01-26T14:23:02.680Z","version":"1.1.31","directory":"/home/francis/Projects/_nvim/opencode.nvim","slug":"sunny-planet","id":"ses_4055037e7ffe7iiIdzWGnWwd0H","summary":{"deletions":0,"additions":0,"files":0}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"session.updated","properties":{"info":{"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","time":{"created":1769437382680,"updated":1769437405755},"title":"Question with other choice for renderer_spec.lua","version":"1.1.31","directory":"/home/francis/Projects/_nvim/opencode.nvim","slug":"sunny-planet","id":"ses_4055037e7ffe7iiIdzWGnWwd0H","summary":{"deletions":0,"additions":0,"files":0}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]}]
+[
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "time": { "created": 1769437382680, "updated": 1769437382680 },
+ "title": "New session - 2026-01-26T14:23:02.680Z",
+ "version": "1.1.31",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "slug": "sunny-planet",
+ "id": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "time": { "created": 1769437392705 },
+ "role": "user",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "msg_bfaafef41001700DjtCwvhFxse",
+ "agent": "build"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "synthetic": true,
+ "text": "Called the Read tool with the following input: {\"filePath\":\"/home/francis/Projects/_nvim/opencode.nvim/tests/replay/renderer_spec.lua\"}",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfaafef42002jckWu6xA2ZV3zg",
+ "messageID": "msg_bfaafef41001700DjtCwvhFxse"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "synthetic": true,
+ "text": "\n00001| local state = require('opencode.state')\n00002| local ui = require('opencode.ui.ui')\n00003| local helpers = require('tests.helpers')\n00004| local output_window = require('opencode.ui.output_window')\n00005| local assert = require('luassert')\n00006| local config = require('opencode.config')\n00007| \n00008| local function assert_output_matches(expected, actual, name)\n00009| local normalized_extmarks = helpers.normalize_namespace_ids(actual.extmarks)\n00010| \n00011| assert.are.equal(\n00012| #expected.lines,\n00013| #actual.lines,\n00014| string.format(\n00015| 'Line count mismatch: expected %d, got %d.\\nFirst difference at index %d:\\n Expected: %s\\n Actual: %s',\n00016| #expected.lines,\n00017| #actual.lines,\n00018| math.min(#expected.lines, #actual.lines) + 1,\n00019| vim.inspect(expected.lines[math.min(#expected.lines, #actual.lines) + 1]),\n00020| vim.inspect(actual.lines[math.min(#expected.lines, #actual.lines) + 1])\n00021| )\n00022| )\n00023| \n00024| for i = 1, #expected.lines do\n00025| assert.are.equal(\n00026| expected.lines[i],\n00027| actual.lines[i],\n00028| string.format(\n00029| 'Line %d mismatch:\\n Expected: %s\\n Actual: %s',\n00030| i,\n00031| vim.inspect(expected.lines[i]),\n00032| vim.inspect(actual.lines[i])\n00033| )\n00034| )\n00035| end\n00036| \n00037| assert.are.equal(\n00038| #expected.extmarks,\n00039| #normalized_extmarks,\n00040| string.format(\n00041| 'Extmark count mismatch: expected %d, got %d.\\nFirst difference at index %d:\\n Expected: %s\\n Actual: %s',\n00042| #expected.extmarks,\n00043| #normalized_extmarks,\n00044| math.min(#expected.extmarks, #normalized_extmarks) + 1,\n00045| vim.inspect(expected.extmarks[math.min(#expected.extmarks, #normalized_extmarks) + 1]),\n00046| vim.inspect(normalized_extmarks[math.min(#expected.extmarks, #normalized_extmarks) + 1])\n00047| )\n00048| )\n00049| \n00050| for i = 1, #expected.extmarks do\n00051| assert.are.same(\n00052| expected.extmarks[i],\n00053| normalized_extmarks[i],\n00054| string.format(\n00055| 'Extmark %d mismatch:\\n Expected: %s\\n Actual: %s',\n00056| i,\n00057| vim.inspect(expected.extmarks[i]),\n00058| vim.inspect(normalized_extmarks[i])\n00059| )\n00060| )\n00061| end\n00062| \n00063| local expected_action_count = expected.actions and #expected.actions or 0\n00064| local actual_action_count = actual.actions and #actual.actions or 0\n00065| \n00066| assert.are.equal(\n00067| expected_action_count,\n00068| actual_action_count,\n00069| string.format('Action count mismatch: expected %d, got %d', expected_action_count, actual_action_count)\n00070| )\n00071| \n00072| if expected.actions then\n00073| -- Sort both arrays for consistent comparison since order doesn't matter\n00074| local function sort_actions(actions)\n00075| local sorted = vim.deepcopy(actions)\n00076| table.sort(sorted, function(a, b)\n00077| return vim.inspect(a) < vim.inspect(b)\n00078| end)\n00079| return sorted\n00080| end\n00081| \n00082| assert.same(\n00083| sort_actions(expected.actions),\n00084| sort_actions(actual.actions),\n00085| string.format(\n00086| 'Actions mismatch:\\n Expected: %s\\n Actual: %s',\n00087| vim.inspect(expected.actions),\n00088| vim.inspect(actual.actions)\n00089| )\n00090| )\n00091| end\n00092| end\n00093| \n00094| describe('renderer unit tests', function()\n00095| local event_subscriptions = {\n00096| 'session.updated',\n00097| 'session.compacted',\n00098| 'session.error',\n00099| 'message.updated',\n00100| 'message.removed',\n00101| 'message.part.updated',\n00102| 'message.part.removed',\n00103| 'permission.updated',\n00104| 'permission.replied',\n00105| 'question.replied',\n00106| 'question.asked',\n00107| 'file.edited',\n00108| 'custom.restore_point.created',\n00109| 'custom.emit_events.finished',\n00110| }\n00111| \n00112| before_each(function()\n00113| require('opencode.event_manager').setup()\n00114| end)\n00115| \n00116| it('subsribes to events correctly', function()\n00117| local renderer = require('opencode.ui.renderer')\n00118| local event_manager = state.event_manager\n00119| \n00120| event_manager.events = {}\n00121| \n00122| renderer.setup_subscriptions()\n00123| \n00124| for _, event_name in ipairs(event_subscriptions) do\n00125| assert.is_true(\n00126| event_manager.events[event_name] ~= nil,\n00127| string.format('Renderer did not subscribe to event: %s', event_name)\n00128| )\n00129| end\n00130| end)\n00131| \n00132| it('unsubsribes from events correctly', function()\n00133| local renderer = require('opencode.ui.renderer')\n00134| local event_manager = state.event_manager\n00135| \n00136| renderer.setup_subscriptions()\n00137| \n00138| renderer.setup_subscriptions(false)\n00139| \n00140| for _, event_name in ipairs(event_subscriptions) do\n00141| assert.is_true(\n00142| vim.tbl_isempty(event_manager.events[event_name]),\n00143| string.format('Renderer did not unsubscribe from event: %s', event_name)\n00144| )\n00145| end\n00146| end)\n00147| end)\n00148| \n00149| describe('renderer functional tests', function()\n00150| config.debug.show_ids = true\n00151| \n00152| before_each(function()\n00153| helpers.replay_setup()\n00154| end)\n00155| \n00156| after_each(function()\n00157| if state.windows then\n00158| ui.close_windows(state.windows)\n00159| end\n00160| end)\n00161| \n00162| local json_files = vim.fn.glob('tests/data/*.json', false, true)\n00163| \n00164| -- Don't do the full session test on these files, usually\n00165| -- because they involve permission prompts\n00166| local skip_full_session = {\n00167| 'permission-prompt',\n00168| 'permission-ask-new',\n00169| 'question-ask',\n00170| 'shifting-and-multiple-perms',\n00171| 'message-removal',\n00172| }\n00173| \n00174| for _, filepath in ipairs(json_files) do\n00175| local name = vim.fn.fnamemodify(filepath, ':t:r')\n00176| \n00177| if not name:match('%.expected$') then\n00178| local expected_path = 'tests/data/' .. name .. '.expected.json'\n00179| \n00180| if vim.fn.filereadable(expected_path) == 1 then\n00181| for i = 1, 2 do\n00182| config.ui.output.rendering.event_collapsing = i == 1 and true or false\n00183| it(\n00184| 'replays '\n00185| .. name\n00186| .. ' correctly (event-by-event, '\n00187| .. (config.ui.output.rendering.event_collapsing and 'collapsing' or 'no collapsing')\n00188| .. ')',\n00189| function()\n00190| local events = helpers.load_test_data(filepath)\n00191| state.active_session = helpers.get_session_from_events(events)\n00192| local expected = helpers.load_test_data(expected_path)\n00193| \n00194| helpers.replay_events(events)\n00195| vim.wait(1000, function()\n00196| return vim.tbl_isempty(state.event_manager.throttling_emitter.queue)\n00197| end)\n00198| \n00199| local actual = helpers.capture_output(state.windows and state.windows.output_buf, output_window.namespace)\n00200| assert_output_matches(expected, actual, name)\n00201| end\n00202| )\n00203| end\n00204| \n00205| if not vim.tbl_contains(skip_full_session, name) then\n00206| it('replays ' .. name .. ' correctly (session)', function()\n00207| local renderer = require('opencode.ui.renderer')\n00208| local events = helpers.load_test_data(filepath)\n00209| state.active_session = helpers.get_session_from_events(events, true)\n00210| local expected = helpers.load_test_data(expected_path)\n00211| \n00212| local session_data = helpers.load_session_from_events(events)\n00213| renderer._render_full_session_data(session_data)\n00214| \n00215| local actual = helpers.capture_output(state.windows and state.windows.output_buf, output_window.namespace)\n00216| assert_output_matches(expected, actual, name)\n00217| end)\n00218| end\n00219| end\n00220| end\n00221| end\n00222| end)\n00223| \n\n(End of file - total 223 lines)\n",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfaafef47001HR3fZ3Ct7nScuT",
+ "messageID": "msg_bfaafef41001700DjtCwvhFxse"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "file",
+ "messageID": "msg_bfaafef41001700DjtCwvhFxse",
+ "url": "file:///home/francis/Projects/_nvim/opencode.nvim/tests/replay/renderer_spec.lua",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "filename": "tests/replay/renderer_spec.lua",
+ "id": "prt_bfaafef47002OES5db7H5px77j",
+ "mime": "text/plain"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "text": "can you use the question tool and ask me a question with an other choice",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfaafef42001XawiVVGpNU0t5E",
+ "messageID": "msg_bfaafef41001700DjtCwvhFxse"
+ }
+ }
+ },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "time": { "created": 1769437382680, "updated": 1769437392735 },
+ "title": "New session - 2026-01-26T14:23:02.680Z",
+ "version": "1.1.31",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "slug": "sunny-planet",
+ "id": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "time": { "created": 1769437392819 },
+ "modelID": "gpt-4.1",
+ "providerID": "github-copilot",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "mode": "build",
+ "cost": 0,
+ "role": "assistant",
+ "tokens": { "input": 0, "output": 0, "reasoning": 0, "cache": { "read": 0, "write": 0 } },
+ "path": {
+ "root": "/home/francis/Projects/_nvim/opencode.nvim",
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "parentID": "msg_bfaafef41001700DjtCwvhFxse",
+ "id": "msg_bfaafefb3001iBSmqfzFffDjCS",
+ "agent": "build"
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "time": { "created": 1769437392705 },
+ "role": "user",
+ "summary": { "diffs": [] },
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "msg_bfaafef41001700DjtCwvhFxse",
+ "agent": "build"
+ }
+ }
+ },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "time": { "created": 1769437382680, "updated": 1769437392883 },
+ "title": "New session - 2026-01-26T14:23:02.680Z",
+ "version": "1.1.31",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "slug": "sunny-planet",
+ "id": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "summary": { "deletions": 0, "additions": 0, "files": 0 }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "snapshot": "617ad65111b912d010a8ea89957a9c5986bc54f0",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfaaff532001RIiCvjxiMht1EK",
+ "messageID": "msg_bfaafefb3001iBSmqfzFffDjCS"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "callID": "call_b4hwTxyb1alO8r2uMlxeB873",
+ "tool": "question",
+ "state": { "status": "pending", "raw": "", "input": {} },
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfaaff539001jCeh626xIXgw9u",
+ "messageID": "msg_bfaafefb3001iBSmqfzFffDjCS"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "question.asked",
+ "properties": {
+ "questions": [
+ {
+ "question": "What is your favorite color?",
+ "header": "Choose your preferred color",
+ "options": [
+ { "description": "A bold, vibrant choice for those who like attention.", "label": "Red" },
+ { "description": "A calm, reliable color suitable for most environments.", "label": "Blue" },
+ { "description": "Symbolizes growth, harmony, and renewal.", "label": "Green" },
+ { "description": "Type your own favorite color.", "label": "Other" }
+ ]
+ }
+ ],
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "tool": { "messageID": "msg_bfaafefb3001iBSmqfzFffDjCS", "callID": "call_b4hwTxyb1alO8r2uMlxeB873" },
+ "id": "que_bfaaff9cc001DnGuMPilJYG9ya"
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "callID": "call_b4hwTxyb1alO8r2uMlxeB873",
+ "tool": "question",
+ "state": {
+ "status": "running",
+ "time": { "start": 1769437395404 },
+ "input": {
+ "questions": [
+ {
+ "question": "What is your favorite color?",
+ "header": "Choose your preferred color",
+ "options": [
+ { "description": "A bold, vibrant choice for those who like attention.", "label": "Red" },
+ { "description": "A calm, reliable color suitable for most environments.", "label": "Blue" },
+ { "description": "Symbolizes growth, harmony, and renewal.", "label": "Green" },
+ { "description": "Type your own favorite color.", "label": "Other" }
+ ]
+ }
+ ]
+ }
+ },
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfaaff539001jCeh626xIXgw9u",
+ "messageID": "msg_bfaafefb3001iBSmqfzFffDjCS"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "time": { "created": 1769437392705 },
+ "role": "user",
+ "summary": { "title": "Question with Other choice", "diffs": [] },
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "msg_bfaafef41001700DjtCwvhFxse",
+ "agent": "build"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "question.replied",
+ "properties": {
+ "answers": [["Red"]],
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "requestID": "que_bfaaff9cc001DnGuMPilJYG9ya"
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "tool",
+ "callID": "call_b4hwTxyb1alO8r2uMlxeB873",
+ "tool": "question",
+ "state": {
+ "metadata": { "answers": [["Red"]], "truncated": false },
+ "time": { "start": 1769437395404, "end": 1769437402416 },
+ "title": "Asked 1 question",
+ "status": "completed",
+ "output": "User has answered your questions: \"What is your favorite color?\"=\"Red\". You can now continue with the user's answers in mind.",
+ "input": {
+ "questions": [
+ {
+ "question": "What is your favorite color?",
+ "header": "Choose your preferred color",
+ "options": [
+ { "description": "A bold, vibrant choice for those who like attention.", "label": "Red" },
+ { "description": "A calm, reliable color suitable for most environments.", "label": "Blue" },
+ { "description": "Symbolizes growth, harmony, and renewal.", "label": "Green" },
+ { "description": "Type your own favorite color.", "label": "Other" }
+ ]
+ }
+ ]
+ }
+ },
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfaaff539001jCeh626xIXgw9u",
+ "messageID": "msg_bfaafefb3001iBSmqfzFffDjCS"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "step-finish",
+ "tokens": { "input": 12775, "output": 150, "reasoning": 0, "cache": { "read": 0, "write": 0 } },
+ "cost": 0,
+ "reason": "tool-calls",
+ "snapshot": "617ad65111b912d010a8ea89957a9c5986bc54f0",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfab01535001wSIZq9GBd5DM3p",
+ "messageID": "msg_bfaafefb3001iBSmqfzFffDjCS"
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "time": { "created": 1769437392819 },
+ "modelID": "gpt-4.1",
+ "providerID": "github-copilot",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "tokens": { "input": 12775, "output": 150, "reasoning": 0, "cache": { "read": 0, "write": 0 } },
+ "mode": "build",
+ "id": "msg_bfaafefb3001iBSmqfzFffDjCS",
+ "role": "assistant",
+ "cost": 0,
+ "path": {
+ "root": "/home/francis/Projects/_nvim/opencode.nvim",
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "parentID": "msg_bfaafef41001700DjtCwvhFxse",
+ "finish": "tool-calls",
+ "agent": "build"
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "time": { "created": 1769437392819, "completed": 1769437402460 },
+ "modelID": "gpt-4.1",
+ "providerID": "github-copilot",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "tokens": { "input": 12775, "output": 150, "reasoning": 0, "cache": { "read": 0, "write": 0 } },
+ "mode": "build",
+ "id": "msg_bfaafefb3001iBSmqfzFffDjCS",
+ "role": "assistant",
+ "cost": 0,
+ "path": {
+ "root": "/home/francis/Projects/_nvim/opencode.nvim",
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "parentID": "msg_bfaafef41001700DjtCwvhFxse",
+ "finish": "tool-calls",
+ "agent": "build"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "time": { "created": 1769437402477 },
+ "modelID": "gpt-4.1",
+ "providerID": "github-copilot",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "mode": "build",
+ "cost": 0,
+ "role": "assistant",
+ "tokens": { "input": 0, "output": 0, "reasoning": 0, "cache": { "read": 0, "write": 0 } },
+ "path": {
+ "root": "/home/francis/Projects/_nvim/opencode.nvim",
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "parentID": "msg_bfaafef41001700DjtCwvhFxse",
+ "id": "msg_bfab0156d001NyMxaTnj6Cml0c",
+ "agent": "build"
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "time": { "created": 1769437392705 },
+ "role": "user",
+ "summary": { "title": "Question with Other choice", "diffs": [] },
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "msg_bfaafef41001700DjtCwvhFxse",
+ "agent": "build"
+ }
+ }
+ },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "time": { "created": 1769437382680, "updated": 1769437402502 },
+ "title": "New session - 2026-01-26T14:23:02.680Z",
+ "version": "1.1.31",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "slug": "sunny-planet",
+ "id": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "summary": { "deletions": 0, "additions": 0, "files": 0 }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "snapshot": "617ad65111b912d010a8ea89957a9c5986bc54f0",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfab01cd9001JINkAnbcXksgNO",
+ "messageID": "msg_bfab0156d001NyMxaTnj6Cml0c"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1769437404381 },
+ "text": "Thank you",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfab01cdd001Y6UnA89vh364ZV",
+ "messageID": "msg_bfab0156d001NyMxaTnj6Cml0c"
+ },
+ "delta": " you"
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1769437404381 },
+ "text": "Thank you! You chose \"Red\" as your favorite color",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfab01cdd001Y6UnA89vh364ZV",
+ "messageID": "msg_bfab0156d001NyMxaTnj6Cml0c"
+ },
+ "delta": " color"
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1769437404381 },
+ "text": "Thank you! You chose \"Red\" as your favorite color. If you have a specific task, question,",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfab01cdd001Y6UnA89vh364ZV",
+ "messageID": "msg_bfab0156d001NyMxaTnj6Cml0c"
+ },
+ "delta": ","
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1769437404381 },
+ "text": "Thank you! You chose \"Red\" as your favorite color. If you have a specific task, question, or want to see this preference used in an example",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfab01cdd001Y6UnA89vh364ZV",
+ "messageID": "msg_bfab0156d001NyMxaTnj6Cml0c"
+ },
+ "delta": " example"
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1769437404381 },
+ "text": "Thank you! You chose \"Red\" as your favorite color. If you have a specific task, question, or want to see this preference used in an example or feature, please let me know how you'd like",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfab01cdd001Y6UnA89vh364ZV",
+ "messageID": "msg_bfab0156d001NyMxaTnj6Cml0c"
+ },
+ "delta": " like"
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1769437404381 },
+ "text": "Thank you! You chose \"Red\" as your favorite color. If you have a specific task, question, or want to see this preference used in an example or feature, please let me know how you'd like to proceed",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfab01cdd001Y6UnA89vh364ZV",
+ "messageID": "msg_bfab0156d001NyMxaTnj6Cml0c"
+ },
+ "delta": " proceed"
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1769437404381 },
+ "text": "Thank you! You chose \"Red\" as your favorite color. If you have a specific task, question, or want to see this preference used in an example or feature, please let me know how you'd like to proceed!",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfab01cdd001Y6UnA89vh364ZV",
+ "messageID": "msg_bfab0156d001NyMxaTnj6Cml0c"
+ },
+ "delta": "!"
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1769437405694, "end": 1769437405694 },
+ "text": "Thank you! You chose \"Red\" as your favorite color. If you have a specific task, question, or want to see this preference used in an example or feature, please let me know how you'd like to proceed!",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfab01cdd001Y6UnA89vh364ZV",
+ "messageID": "msg_bfab0156d001NyMxaTnj6Cml0c"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "type": "step-finish",
+ "tokens": { "input": 874, "output": 47, "reasoning": 0, "cache": { "read": 12032, "write": 0 } },
+ "cost": 0,
+ "reason": "stop",
+ "snapshot": "617ad65111b912d010a8ea89957a9c5986bc54f0",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "prt_bfab021ff001EzP7TpA5rv7aTl",
+ "messageID": "msg_bfab0156d001NyMxaTnj6Cml0c"
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "time": { "created": 1769437402477 },
+ "modelID": "gpt-4.1",
+ "providerID": "github-copilot",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "tokens": { "input": 874, "output": 47, "reasoning": 0, "cache": { "read": 12032, "write": 0 } },
+ "mode": "build",
+ "id": "msg_bfab0156d001NyMxaTnj6Cml0c",
+ "role": "assistant",
+ "cost": 0,
+ "path": {
+ "root": "/home/francis/Projects/_nvim/opencode.nvim",
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "parentID": "msg_bfaafef41001700DjtCwvhFxse",
+ "finish": "stop",
+ "agent": "build"
+ }
+ }
+ },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "time": { "created": 1769437402477, "completed": 1769437405729 },
+ "modelID": "gpt-4.1",
+ "providerID": "github-copilot",
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "tokens": { "input": 874, "output": 47, "reasoning": 0, "cache": { "read": 12032, "write": 0 } },
+ "mode": "build",
+ "id": "msg_bfab0156d001NyMxaTnj6Cml0c",
+ "role": "assistant",
+ "cost": 0,
+ "path": {
+ "root": "/home/francis/Projects/_nvim/opencode.nvim",
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "parentID": "msg_bfaafef41001700DjtCwvhFxse",
+ "finish": "stop",
+ "agent": "build"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "model": { "providerID": "github-copilot", "modelID": "gpt-4.1" },
+ "time": { "created": 1769437392705 },
+ "role": "user",
+ "summary": { "title": "Question with Other choice", "diffs": [] },
+ "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "id": "msg_bfaafef41001700DjtCwvhFxse",
+ "agent": "build"
+ }
+ }
+ },
+ { "type": "session.idle", "properties": { "sessionID": "ses_4055037e7ffe7iiIdzWGnWwd0H" } },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "time": { "created": 1769437382680, "updated": 1769437405755 },
+ "title": "New session - 2026-01-26T14:23:02.680Z",
+ "version": "1.1.31",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "slug": "sunny-planet",
+ "id": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "summary": { "deletions": 0, "additions": 0, "files": 0 }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "time": { "created": 1769437382680, "updated": 1769437405755 },
+ "title": "Question with other choice for renderer_spec.lua",
+ "version": "1.1.31",
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "slug": "sunny-planet",
+ "id": "ses_4055037e7ffe7iiIdzWGnWwd0H",
+ "summary": { "deletions": 0, "additions": 0, "files": 0 }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] }
+]
diff --git a/tests/data/question-ask.expected.json b/tests/data/question-ask.expected.json
index 04f4ae07..03f33a89 100644
--- a/tests/data/question-ask.expected.json
+++ b/tests/data/question-ask.expected.json
@@ -1 +1,472 @@
-{"actions":[],"extmarks":[[1,1,0,{"right_gravity":true,"virt_text_win_col":-3,"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2026-01-26 14:06:19)","OpencodeHint"],[" [msg_bfaa078a2001RUYhlKZhSlyWeF]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"priority":10}],[2,2,0,{"right_gravity":true,"virt_text_win_col":-3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[3,3,0,{"right_gravity":true,"virt_text_win_col":-3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[4,4,0,{"right_gravity":true,"virt_text_win_col":-3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[5,5,0,{"right_gravity":true,"virt_text_win_col":-3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[6,6,0,{"right_gravity":true,"virt_text_win_col":-3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[7,8,0,{"right_gravity":true,"virt_text_win_col":-3,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2026-01-26 14:06:19)","OpencodeHint"],[" [msg_bfaa078e7001qc33BqBlqzHv8X]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"priority":10}],[8,13,0,{"right_gravity":true,"virt_text_win_col":-3,"virt_text":[[" ","OpencodeMessageRoleSystem"],[" "],["SYSTEM","OpencodeMessageRoleSystem"],["","OpencodeHint"],["","OpencodeHint"],[" [question-display-message]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"priority":10}],[9,15,0,{"right_gravity":true,"priority":4096,"line_hl_group":"OpencodeQuestionTitle","ns_id":3}],[10,15,0,{"right_gravity":true,"virt_text_win_col":-2,"virt_text":[["▌","OpencodeQuestionBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[11,16,0,{"right_gravity":true,"virt_text_win_col":-2,"virt_text":[["▌","OpencodeQuestionBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[12,17,0,{"right_gravity":true,"virt_text_win_col":-2,"virt_text":[["▌","OpencodeQuestionBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[13,18,0,{"right_gravity":true,"virt_text_win_col":-2,"virt_text":[["▌","OpencodeQuestionBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[14,19,0,{"right_gravity":true,"priority":4096,"line_hl_group":"OpencodeDialogOptionHover","ns_id":3}],[15,19,0,{"right_gravity":true,"virt_text_win_col":-2,"virt_text":[["▌","OpencodeQuestionBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[16,19,2,{"virt_text":[["› ","OpencodeDialogOptionHover"]],"virt_text_hide":false,"ns_id":3,"right_gravity":true,"virt_text_pos":"overlay","virt_text_repeat_linebreak":false,"priority":4096}],[17,20,0,{"right_gravity":true,"virt_text_win_col":-2,"virt_text":[["▌","OpencodeQuestionBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[18,21,0,{"right_gravity":true,"virt_text_win_col":-2,"virt_text":[["▌","OpencodeQuestionBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[19,22,0,{"right_gravity":true,"virt_text_win_col":-2,"virt_text":[["▌","OpencodeQuestionBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[20,23,0,{"right_gravity":true,"virt_text_win_col":-2,"virt_text":[["▌","OpencodeQuestionBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}]],"lines":["----","","","[`lua/opencode/ui/renderer.lua`](lua/opencode/ui/renderer.lua)","","can you use the question tool and ask me a question with an other choice","","----","","","** question** ","","----","",""," Question","","What is your favorite color?",""," 1. Red - The color red "," 2. Blue - The color blue"," 3. Other - Any color not listed","","Navigate: `j`/`k` or `↑`/`↓` Select: `` or `1-3` Dismiss: ``","",""],"timestamp":1769441972}
+{
+ "actions": [],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2026-01-26 14:06:19)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_bfaa078a2001RUYhlKZhSlyWeF]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 2,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 3,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 4,
+ 4,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 5,
+ 5,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 6,
+ 6,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 7,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-4.1",
+ "OpencodeHint"
+ ],
+ [
+ " (2026-01-26 14:06:19)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_bfaa078e7001qc33BqBlqzHv8X]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 8,
+ 13,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleSystem"
+ ],
+ [
+ " "
+ ],
+ [
+ "SYSTEM",
+ "OpencodeMessageRoleSystem"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " [question-display-message]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 9,
+ 15,
+ 0,
+ {
+ "line_hl_group": "OpencodeQuestionTitle",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true
+ }
+ ],
+ [
+ 10,
+ 15,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeQuestionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 11,
+ 16,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeQuestionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 12,
+ 17,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeQuestionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 13,
+ 18,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeQuestionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 14,
+ 19,
+ 0,
+ {
+ "line_hl_group": "OpencodeDialogOptionHover",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true
+ }
+ ],
+ [
+ 15,
+ 19,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeQuestionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 16,
+ 19,
+ 2,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "› ",
+ "OpencodeDialogOptionHover"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "overlay",
+ "virt_text_repeat_linebreak": false
+ }
+ ],
+ [
+ 17,
+ 20,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeQuestionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 18,
+ 21,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeQuestionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 19,
+ 22,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeQuestionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 20,
+ 23,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeQuestionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "[`lua/opencode/ui/renderer.lua`](lua/opencode/ui/renderer.lua)",
+ "",
+ "can you use the question tool and ask me a question with an other choice",
+ "",
+ "----",
+ "",
+ "",
+ "** question** ",
+ "",
+ "----",
+ "",
+ "",
+ " Question",
+ "",
+ "What is your favorite color?",
+ "",
+ " 1. Red - The color red ",
+ " 2. Blue - The color blue",
+ " 3. Other - Any color not listed",
+ "",
+ "Navigate: `j`/`k` or `↑`/`↓` Select: `` or `1-3` Dismiss: ``",
+ "",
+ ""
+ ],
+ "timestamp": 1770748579
+}
\ No newline at end of file
diff --git a/tests/data/question-ask.json b/tests/data/question-ask.json
index f3249bba..40e42689 100644
--- a/tests/data/question-ask.json
+++ b/tests/data/question-ask.json
@@ -1 +1,306 @@
-[{"type":"session.updated","properties":{"info":{"directory":"/home/francis/Projects/_nvim/opencode.nvim","version":"1.1.31","slug":"calm-lagoon","id":"ses_4055f967bffeIHf3DnP0xntmxD","title":"New session - 2026-01-26T14:06:15.428Z","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","time":{"created":1769436375428,"updated":1769436375428}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"time":{"created":1769436379298},"id":"msg_bfaa078a2001RUYhlKZhSlyWeF","sessionID":"ses_4055f967bffeIHf3DnP0xntmxD","role":"user","model":{"modelID":"gpt-4.1","providerID":"github-copilot"},"agent":"build"}}},{"type":"message.part.updated","properties":{"part":{"synthetic":true,"messageID":"msg_bfaa078a2001RUYhlKZhSlyWeF","sessionID":"ses_4055f967bffeIHf3DnP0xntmxD","text":"Called the Read tool with the following input: {\"filePath\":\"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/renderer.lua\"}","type":"text","id":"prt_bfaa078a5001Pni4eaodfXL6o6"}}},{"type":"message.part.updated","properties":{"part":{"synthetic":true,"messageID":"msg_bfaa078a2001RUYhlKZhSlyWeF","sessionID":"ses_4055f967bffeIHf3DnP0xntmxD","text":"\n00001| local state = require('opencode.state')\n00002| local config = require('opencode.config')\n00003| local formatter = require('opencode.ui.formatter')\n00004| local output_window = require('opencode.ui.output_window')\n00005| local permission_window = require('opencode.ui.permission_window')\n00006| local Promise = require('opencode.promise')\n00007| local RenderState = require('opencode.ui.render_state')\n00008| \n00009| local M = {\n00010| _prev_line_count = 0,\n00011| _render_state = RenderState.new(),\n00012| _last_part_formatted = {\n00013| part_id = nil,\n00014| formatted_data = nil --[[@as Output|nil]],\n00015| },\n00016| }\n00017| \n00018| local trigger_on_data_rendered = require('opencode.util').debounce(function()\n00019| local cb_type = type(config.ui.output.rendering.on_data_rendered)\n00020| \n00021| if cb_type == 'boolean' then\n00022| return\n00023| end\n00024| \n00025| if not state.windows or not state.windows.output_buf or not state.windows.output_win then\n00026| return\n00027| end\n00028| \n00029| if cb_type == 'function' then\n00030| pcall(config.ui.output.rendering.on_data_rendered, state.windows.output_buf, state.windows.output_win)\n00031| elseif vim.fn.exists(':RenderMarkdown') > 0 then\n00032| vim.cmd(':RenderMarkdown')\n00033| elseif vim.fn.exists(':Markview') > 0 then\n00034| vim.cmd(':Markview render ' .. state.windows.output_buf)\n00035| end\n00036| end, config.ui.output.rendering.markdown_debounce_ms or 250)\n00037| \n00038| ---Reset renderer state\n00039| function M.reset()\n00040| M._prev_line_count = 0\n00041| M._render_state:reset()\n00042| M._last_part_formatted = { part_id = nil, formatted_data = nil }\n00043| \n00044| output_window.clear()\n00045| \n00046| state.messages = {}\n00047| state.last_user_message = nil\n00048| state.tokens_count = 0\n00049| \n00050| local permissions = state.pending_permissions or {}\n00051| if #permissions and state.api_client then\n00052| for _, permission in ipairs(permissions) do\n00053| require('opencode.api').permission_deny(permission)\n00054| end\n00055| end\n00056| permission_window.clear_all()\n00057| state.pending_permissions = {}\n00058| \n00059| trigger_on_data_rendered()\n00060| end\n00061| \n00062| ---Set up event subscriptions\n00063| ---@param subscribe? boolean false to unsubscribe\n00064| function M.setup_subscriptions(subscribe)\n00065| subscribe = subscribe == nil and true or subscribe\n00066| \n00067| if subscribe then\n00068| state.subscribe('is_opencode_focused', M.on_focus_changed)\n00069| state.subscribe('active_session', M.on_session_changed)\n00070| else\n00071| state.unsubscribe('is_opencode_focused', M.on_focus_changed)\n00072| state.unsubscribe('active_session', M.on_session_changed)\n00073| end\n00074| \n00075| if not state.event_manager then\n00076| return\n00077| end\n00078| \n00079| local event_subscriptions = {\n00080| { 'session.updated', M.on_session_updated },\n00081| { 'session.compacted', M.on_session_compacted },\n00082| { 'session.error', M.on_session_error },\n00083| { 'message.updated', M.on_message_updated },\n00084| { 'message.removed', M.on_message_removed },\n00085| { 'message.part.updated', M.on_part_updated },\n00086| { 'message.part.removed', M.on_part_removed },\n00087| { 'permission.updated', M.on_permission_updated },\n00088| { 'permission.asked', M.on_permission_updated },\n00089| { 'permission.replied', M.on_permission_replied },\n00090| { 'question.asked', M.on_question_asked },\n00091| { 'question.replied', M.clear_question_display },\n00092| { 'question.rejected', M.clear_question_display },\n00093| { 'file.edited', M.on_file_edited },\n00094| { 'custom.restore_point.created', M.on_restore_points },\n00095| { 'custom.emit_events.finished', M.on_emit_events_finished },\n00096| }\n00097| \n00098| for _, sub in ipairs(event_subscriptions) do\n00099| if subscribe then\n00100| state.event_manager:subscribe(sub[1], sub[2])\n00101| else\n00102| state.event_manager:unsubscribe(sub[1], sub[2])\n00103| end\n00104| end\n00105| end\n00106| \n00107| ---Clean up and teardown renderer. Unsubscribes from all events\n00108| function M.teardown()\n00109| M.setup_subscriptions(false)\n00110| M.reset()\n00111| end\n00112| \n00113| ---Fetch full session messages from server\n00114| ---@return Promise Promise resolving to list of OpencodeMessage\n00115| local function fetch_session()\n00116| local session = state.active_session\n00117| if not session or not session or session == '' then\n00118| return Promise.new():resolve(nil)\n00119| end\n00120| \n00121| state.last_user_message = nil\n00122| return require('opencode.session').get_messages(session)\n00123| end\n00124| \n00125| ---Request all of the session data from the opencode server and render it\n00126| ---@return Promise\n00127| function M.render_full_session()\n00128| if not output_window.mounted() or not state.api_client then\n00129| return Promise.new():resolve(nil)\n00130| end\n00131| \n00132| return fetch_session():and_then(M._render_full_session_data)\n00133| end\n00134| \n00135| function M._render_full_session_data(session_data)\n00136| M.reset()\n00137| \n00138| if not state.active_session or not state.messages then\n00139| return\n00140| end\n00141| \n00142| local revert_index = nil\n00143| \n00144| -- if we're loading a session and there's no currently selected model, set it\n00145| -- from the messages\n00146| local set_mode_from_messages = not state.current_model\n00147| \n00148| for i, msg in ipairs(session_data) do\n00149| if state.active_session.revert and state.active_session.revert.messageID == msg.info.id then\n00150| revert_index = i\n00151| end\n00152| \n00153| M.on_message_updated({ info = msg.info }, revert_index)\n00154| \n00155| for _, part in ipairs(msg.parts or {}) do\n00156| M.on_part_updated({ part = part }, revert_index)\n00157| end\n00158| end\n00159| \n00160| if revert_index then\n00161| M._write_formatted_data(formatter._format_revert_message(state.messages, revert_index))\n00162| end\n00163| \n00164| if set_mode_from_messages then\n00165| M._set_model_and_mode_from_messages()\n00166| end\n00167| M.scroll_to_bottom()\n00168| \n00169| if config.hooks and config.hooks.on_session_loaded then\n00170| pcall(config.hooks.on_session_loaded, state.active_session)\n00171| end\n00172| end\n00173| \n00174| ---Append permissions display as a fake part at the end\n00175| function M.render_permissions_display()\n00176| local fake_message = {\n00177| info = {\n00178| id = 'permission-display-message',\n00179| sessionID = state.active_session and state.active_session.id or '',\n00180| role = 'system',\n00181| },\n00182| parts = {},\n00183| }\n00184| M.on_message_updated(fake_message)\n00185| \n00186| local fake_part = {\n00187| id = 'permission-display-part',\n00188| messageID = 'permission-display-message',\n00189| sessionID = state.active_session and state.active_session.id or '',\n00190| type = 'permissions-display',\n00191| }\n00192| \n00193| local permissions = permission_window.get_all_permissions()\n00194| if #permissions > 0 then\n00195| M.on_part_updated({ part = fake_part })\n00196| end\n00197| end\n00198| \n00199| function M.clear_question_display()\n00200| local question_window = require('opencode.ui.question_window')\n00201| question_window.clear_question()\n00202| M._remove_part_from_buffer('question-display-part')\n00203| M._remove_message_from_buffer('question-display-message')\n00204| end\n00205| \n00206| ---Render question display as a fake part\n00207| function M.render_question_display()\n00208| local question_window = require('opencode.ui.question_window')\n00209| \n00210| local current_question = question_window._current_question\n00211| \n00212| if not question_window.has_question() or not current_question or not current_question.id then\n00213| M._remove_part_from_buffer('question-display-part')\n00214| M._remove_message_from_buffer('question-display-message')\n00215| return\n00216| end\n00217| \n00218| local message_id = 'question-display-message'\n00219| local part_id = 'question-display-part'\n00220| \n00221| local fake_message = {\n00222| info = {\n00223| id = message_id,\n00224| sessionID = state.active_session and state.active_session.id or '',\n00225| role = 'system',\n00226| },\n00227| parts = {},\n00228| }\n00229| M.on_message_updated(fake_message)\n00230| \n00231| local fake_part = {\n00232| id = part_id,\n00233| messageID = message_id,\n00234| sessionID = state.active_session and state.active_session.id or '',\n00235| type = 'questions-display',\n00236| }\n00237| \n00238| M.on_part_updated({ part = fake_part })\n00239| M._redraw()\n00240| M.scroll_to_bottom(true)\n00241| end\n00242| \n00243| function M._redraw()\n00244| if state.windows and state.windows.output_win and vim.api.nvim_win_is_valid(state.windows.output_win) then\n00245| vim.api.nvim_win_call(state.windows.output_win, function()\n00246| vim.cmd('redraw')\n00247| end)\n00248| end\n00249| end\n00250| \n00251| ---Render lines as the entire output buffer\n00252| ---@param lines any\n00253| function M.render_lines(lines)\n00254| local output = require('opencode.ui.output'):new()\n00255| output.lines = lines\n00256| M.render_output(output)\n00257| end\n00258| \n00259| ---Sets the entire output buffer based on output_data\n00260| ---@param output_data Output Output object from formatter\n00261| function M.render_output(output_data)\n00262| if not output_window.mounted() then\n00263| return\n00264| end\n00265| \n00266| local lines = output_data.lines or {}\n00267| \n00268| output_window.set_lines(lines)\n00269| output_window.clear_extmarks()\n00270| output_window.set_extmarks(output_data.extmarks)\n00271| M.scroll_to_bottom()\n00272| end\n00273| \n00274| ---Called when EventManager has finished emitting a batch of events\n00275| function M.on_emit_events_finished()\n00276| M.scroll_to_bottom()\n00277| end\n00278| \n00279| ---Find the most recently used model from the messages\n00280| function M._set_model_and_mode_from_messages()\n00281| if not state.messages then\n00282| return\n00283| end\n00284| \n00285| for i = #state.messages, 1, -1 do\n00286| local message = state.messages[i]\n00287| \n00288| if message and message.info then\n00289| if message.info.modelID and message.info.providerID then\n00290| state.current_model = message.info.providerID .. '/' .. message.info.modelID\n00291| if message.info.mode then\n00292| state.current_mode = message.info.mode\n00293| end\n00294| return\n00295| end\n00296| end\n00297| end\n00298| \n00299| -- we didn't find a model from any messages, set it to the default\n00300| require('opencode.core').initialize_current_model()\n00301| end\n00302| \n00303| ---Auto-scroll to bottom if user was already at bottom\n00304| ---Respects cursor position if user has scrolled up\n00305| ---@param force? boolean If true, scroll regardless of current position\n00306| function M.scroll_to_bottom(force)\n00307| if not state.windows or not state.windows.output_buf or not state.windows.output_win then\n00308| return\n00309| end\n00310| \n00311| if not vim.api.nvim_win_is_valid(state.windows.output_win) then\n00312| return\n00313| end\n00314| \n00315| local ok, line_count = pcall(vim.api.nvim_buf_line_count, state.windows.output_buf)\n00316| if not ok or line_count == 0 then\n00317| return\n00318| end\n00319| \n00320| local prev_line_count = M._prev_line_count or 0\n00321| \n00322| ---@cast line_count integer\n00323| M._prev_line_count = line_count\n00324| \n00325| trigger_on_data_rendered()\n00326| \n00327| -- Determine if we should scroll to bottom\n00328| local should_scroll = force == true\n00329| \n00330| if not should_scroll then\n00331| -- Always scroll on initial render\n00332| if prev_line_count == 0 then\n00333| should_scroll = true\n00334| -- Scroll if user is at bottom (respects manual scroll position)\n00335| elseif output_window.viewport_at_bottom then\n00336| should_scroll = true\n00337| end\n00338| end\n00339| \n00340| if should_scroll then\n00341| vim.api.nvim_win_set_cursor(state.windows.output_win, { line_count, 0 })\n00342| -- Use zb to position the cursor line at the bottom of the visible window\n00343| vim.api.nvim_win_call(state.windows.output_win, function()\n00344| vim.cmd('normal! zb')\n00345| end)\n00346| output_window.viewport_at_bottom = true\n00347| else\n00348| -- User has scrolled up, don't scroll\n00349| output_window.viewport_at_bottom = false\n00350| end\n00351| end\n00352| \n00353| ---Write data to output_buf, including normal text and extmarks\n00354| ---@param formatted_data Output Formatted data as Output object\n00355| ---@param part_id? string Optional part ID to store actions\n00356| ---@param start_line? integer Optional line to insert at (shifts content down). If nil, appends to end of buffer.\n00357| ---@return {line_start: integer, line_end: integer}? Range where data was written\n00358| function M._write_formatted_data(formatted_data, part_id, start_line)\n00359| if not state.windows or not state.windows.output_buf then\n00360| return\n00361| end\n00362| \n00363| local buf = state.windows.output_buf\n00364| local is_insertion = start_line ~= nil\n00365| local target_line = start_line or output_window.get_buf_line_count()\n00366| local new_lines = formatted_data.lines\n00367| local extmarks = formatted_data.extmarks\n00368| \n00369| if #new_lines == 0 or not buf then\n00370| return nil\n00371| end\n00372| \n00373| if is_insertion then\n00374| output_window.set_lines(new_lines, target_line, target_line)\n00375| else\n00376| local extra_newline = vim.tbl_extend('keep', {}, new_lines)\n00377| table.insert(extra_newline, '')\n00378| target_line = target_line - 1\n00379| output_window.set_lines(extra_newline, target_line)\n00380| end\n00381| \n00382| -- update actions and extmarks after the insertion because that may\n00383| -- adjust target_line (e.g. when we we're replacing the double newline at\n00384| -- the end)\n00385| \n00386| if part_id and formatted_data.actions then\n00387| M._render_state:add_actions(part_id, formatted_data.actions, target_line)\n00388| end\n00389| \n00390| output_window.set_extmarks(extmarks, target_line)\n00391| \n00392| return {\n00393| line_start = target_line,\n00394| line_end = target_line + #new_lines - 1,\n00395| }\n00396| end\n00397| \n00398| ---Insert new part, either at end of buffer or in the middle for out-of-order parts\n00399| ---@param part_id string Part ID\n00400| ---@param formatted_data Output Formatted data as Output object\n00401| ---@return boolean Success status\n00402| function M._insert_part_to_buffer(part_id, formatted_data)\n00403| local cached = M._render_state:get_part(part_id)\n00404| if not cached then\n00405| return false\n00406| end\n00407| \n00408| if #formatted_data.lines == 0 then\n00409| return true\n00410| end\n00411| \n00412| local is_current_message = state.current_message\n00413| and state.current_message.info\n00414| and state.current_message.info.id == cached.message_id\n00415| \n00416| if is_current_message then\n00417| -- NOTE: we're inserting a part for the current message, just add it to the end\n00418| \n00419| local range = M._write_formatted_data(formatted_data, part_id)\n00420| if not range then\n00421| return false\n00422| end\n00423| \n00424| M._render_state:set_part(cached.part, range.line_start, range.line_end)\n00425| \n00426| M._last_part_formatted = { part_id = part_id, formatted_data = formatted_data }\n00427| \n00428| return true\n00429| end\n00430| \n00431| -- NOTE: We're inserting a part for the first time for a previous message. We need to find\n00432| -- the insertion line (after the last part of this message or after the message header if\n00433| -- no parts).\n00434| local insertion_line = M._get_insertion_point_for_part(part_id, cached.message_id)\n00435| if not insertion_line then\n00436| return false\n00437| end\n00438| \n00439| local range = M._write_formatted_data(formatted_data, part_id, insertion_line)\n00440| if not range then\n00441| return false\n00442| end\n00443| \n00444| local line_count = #formatted_data.lines\n00445| M._render_state:shift_all(insertion_line, line_count)\n00446| \n00447| M._render_state:set_part(cached.part, range.line_start, range.line_end)\n00448| \n00449| return true\n00450| end\n00451| \n00452| ---Replace existing part in buffer\n00453| ---Adjusts line positions of subsequent parts if line count changes\n00454| ---@param part_id string Part ID\n00455| ---@param formatted_data Output Formatted data as Output object\n00456| ---@return boolean Success status\n00457| function M._replace_part_in_buffer(part_id, formatted_data)\n00458| local cached = M._render_state:get_part(part_id)\n00459| if not cached or not cached.line_start or not cached.line_end then\n00460| return false\n00461| end\n00462| \n00463| local new_lines = formatted_data.lines\n00464| local new_line_count = #new_lines\n00465| \n00466| local old_formatted = M._last_part_formatted\n00467| local can_optimize = old_formatted\n00468| and old_formatted.part_id == part_id\n00469| and old_formatted.formatted_data\n00470| and old_formatted.formatted_data.lines\n00471| \n00472| local lines_to_write = new_lines\n00473| local write_start_line = cached.line_start\n00474| \n00475| if can_optimize then\n00476| -- NOTE: This is an optimization to only replace the lines that are different\n00477| -- if we're replacing the most recently formatted part.\n00478| \n00479| ---@cast old_formatted { formatted_data: { lines: string[] } }\n00480| local old_lines = old_formatted.formatted_data.lines\n00481| local first_diff_line = nil\n00482| \n00483| -- Find the first line that's different\n00484| for i = 1, math.min(#old_lines, new_line_count) do\n00485| if old_lines[i] ~= new_lines[i] then\n00486| first_diff_line = i\n00487| break\n00488| end\n00489| end\n00490| \n00491| if not first_diff_line and new_line_count > #old_lines then\n00492| -- The old lines all matched but maybe there are more new lines\n00493| first_diff_line = #old_lines + 1\n00494| end\n00495| \n00496| if first_diff_line then\n00497| lines_to_write = vim.list_slice(new_lines, first_diff_line, new_line_count)\n00498| write_start_line = cached.line_start + first_diff_line - 1\n00499| elseif new_line_count == #old_lines then\n00500| -- Nothing was different, so we're done\n00501| M._last_part_formatted = { part_id = part_id, formatted_data = formatted_data }\n00502| return true\n00503| end\n00504| end\n00505| \n00506| M._render_state:clear_actions(part_id)\n00507| \n00508| output_window.clear_extmarks(cached.line_start - 1, cached.line_end + 1)\n00509| output_window.set_lines(lines_to_write, write_start_line, cached.line_end + 1)\n00510| \n00511| local new_line_end = cached.line_start + new_line_count - 1\n00512| \n00513| output_window.set_extmarks(formatted_data.extmarks, cached.line_start)\n00514| \n00515| if formatted_data.actions then\n00516| M._render_state:add_actions(part_id, formatted_data.actions, cached.line_start + 1)\n00517| end\n00518| \n00519| M._render_state:update_part_lines(part_id, cached.line_start, new_line_end)\n00520| \n00521| M._last_part_formatted = { part_id = part_id, formatted_data = formatted_data }\n00522| \n00523| return true\n00524| end\n00525| \n00526| ---Remove part from buffer and adjust subsequent line positions\n00527| ---@param part_id string Part ID\n00528| function M._remove_part_from_buffer(part_id)\n00529| local cached = M._render_state:get_part(part_id)\n00530| if not cached or not cached.line_start or not cached.line_end then\n00531| return\n00532| end\n00533| \n00534| if not state.windows or not state.windows.output_buf then\n00535| return\n00536| end\n00537| \n00538| output_window.clear_extmarks(cached.line_start - 1, cached.line_end)\n00539| output_window.set_lines({}, cached.line_start - 1, cached.line_end)\n00540| \n00541| M._render_state:remove_part(part_id)\n00542| end\n00543| \n00544| ---Remove message header from buffer and adjust subsequent line positions\n00545| ---@param message_id string Message ID\n00546| function M._remove_message_from_buffer(message_id)\n00547| local cached = M._render_state:get_message(message_id)\n00548| if not cached or not cached.line_start or not cached.line_end then\n00549| return\n00550| end\n00551| \n00552| if not state.windows or not state.windows.output_buf then\n00553| return\n00554| end\n00555| \n00556| output_window.clear_extmarks(cached.line_start - 1, cached.line_end)\n00557| output_window.set_lines({}, cached.line_start - 1, cached.line_end)\n00558| \n00559| M._render_state:remove_message(message_id)\n00560| end\n00561| \n00562| ---Adds a message (most likely just a header) to the buffer\n00563| ---@param message OpencodeMessage Message to add\n00564| function M._add_message_to_buffer(message)\n00565| local header_data = formatter.format_message_header(message)\n00566| local range = M._write_formatted_data(header_data)\n00567| \n00568| if range then\n00569| M._render_state:set_message(message, range.line_start, range.line_end)\n00570| end\n00571| end\n00572| \n00573| ---Replace existing message header in buffer\n00574| ---@param message_id string Message ID\n00575| ---@param formatted_data Output Formatted header as Output object\n00576| ---@return boolean Success status\n00577| function M._replace_message_in_buffer(message_id, formatted_data)\n00578| local cached = M._render_state:get_message(message_id)\n00579| if not cached or not cached.line_start or not cached.line_end then\n00580| return false\n00581| end\n00582| \n00583| local new_lines = formatted_data.lines\n00584| local new_line_count = #new_lines\n00585| \n00586| output_window.clear_extmarks(cached.line_start, cached.line_end + 1)\n00587| output_window.set_lines(new_lines, cached.line_start, cached.line_end + 1)\n00588| output_window.set_extmarks(formatted_data.extmarks, cached.line_start)\n00589| \n00590| local old_line_end = cached.line_end\n00591| local new_line_end = cached.line_start + new_line_count - 1\n00592| \n00593| M._render_state:set_message(cached.message, cached.line_start, new_line_end)\n00594| \n00595| local delta = new_line_end - old_line_end\n00596| if delta ~= 0 then\n00597| M._render_state:shift_all(old_line_end + 1, delta)\n00598| end\n00599| \n00600| return true\n00601| end\n00602| \n00603| ---Event handler for message.updated events\n00604| ---Creates new message or updates existing message info\n00605| ---@param message {info: MessageInfo} Event properties\n00606| ---@param revert_index? integer Revert index in session, if applicable\n00607| function M.on_message_updated(message, revert_index)\n00608| if not state.active_session or not state.messages then\n00609| return\n00610| end\n00611| \n00612| local msg = message --[[@as OpencodeMessage]]\n00613| if not msg or not msg.info or not msg.info.id or not msg.info.sessionID then\n00614| return\n00615| end\n00616| \n00617| if state.active_session.id ~= msg.info.sessionID then\n00618| ---@TODO This is probably a child session message, handle differently?\n00619| -- vim.notify('Session id does not match, discarding message: ' .. vim.inspect(message), vim.log.levels.WARN)\n00620| return\n00621| end\n00622| \n00623| local rendered_message = M._render_state:get_message(msg.info.id)\n00624| local found_msg = rendered_message and rendered_message.message\n00625| \n00626| if revert_index then\n00627| if not found_msg then\n00628| table.insert(state.messages, msg)\n00629| end\n00630| M._render_state:set_message(msg, 0, 0)\n00631| return\n00632| end\n00633| \n00634| if found_msg then\n00635| local error_changed = not vim.deep_equal(found_msg.info.error, msg.info.error)\n00636| \n00637| found_msg.info = msg.info\n00638| \n00639| --- NOTE: error handling is a bit messy because errors come in on messages\n00640| --- but we want to display the error at the end. In this case, we an error\n00641| --- was added to this message. We find the last part and re-render it to\n00642| --- display the message. If there are no parts, we'll re-render the message\n00643| \n00644| if error_changed and not revert_index then\n00645| local last_part_id = M._get_last_part_for_message(found_msg)\n00646| if last_part_id then\n00647| M._rerender_part(last_part_id)\n00648| else\n00649| local header_data = formatter.format_message_header(found_msg)\n00650| M._replace_message_in_buffer(msg.info.id, header_data)\n00651| end\n00652| end\n00653| else\n00654| table.insert(state.messages, msg)\n00655| \n00656| M._add_message_to_buffer(msg)\n00657| \n00658| state.current_message = msg\n00659| if message.info.role == 'user' then\n00660| state.last_user_message = msg\n00661| end\n00662| end\n00663| \n00664| M._update_stats_from_message(msg)\n00665| end\n00666| \n00667| ---Event handler for message.part.updated events\n00668| ---Inserts new parts or replaces existing parts in buffer\n00669| ---@param properties {part: OpencodeMessagePart} Event properties\n00670| ---@param revert_index? integer Revert index in session, if applicable\n00671| function M.on_part_updated(properties, revert_index)\n00672| if not properties or not properties.part or not state.active_session then\n00673| return\n00674| end\n00675| \n00676| local part = properties.part\n00677| if not part.id or not part.messageID or not part.sessionID then\n00678| return\n00679| end\n00680| \n00681| if state.active_session.id ~= part.sessionID then\n00682| ---@TODO This is probably a child session part, handle differently?\n00683| -- vim.notify('Session id does not match, discarding part: ' .. vim.inspect(part), vim.log.levels.WARN)\n00684| return\n00685| end\n00686| \n00687| local rendered_message = M._render_state:get_message(part.messageID)\n00688| if not rendered_message or not rendered_message.message then\n00689| vim.notify('Could not find message for part: ' .. vim.inspect(part), vim.log.levels.WARN)\n00690| return\n00691| end\n00692| \n00693| local message = rendered_message.message\n00694| \n00695| message.parts = message.parts or {}\n00696| \n00697| local part_data = M._render_state:get_part(part.id)\n00698| local is_new_part = not part_data\n00699| \n00700| local prev_last_part_id = M._get_last_part_for_message(message)\n00701| local is_last_part = is_new_part or (prev_last_part_id == part.id)\n00702| \n00703| if is_new_part then\n00704| table.insert(message.parts, part)\n00705| else\n00706| for i = #message.parts, 1, -1 do\n00707| if message.parts[i].id == part.id then\n00708| message.parts[i] = part\n00709| break\n00710| end\n00711| end\n00712| end\n00713| \n00714| if part.type == 'step-start' or part.type == 'step-finish' then\n00715| return\n00716| end\n00717| \n00718| if is_new_part then\n00719| M._render_state:set_part(part)\n00720| else\n00721| local rendered_part = M._render_state:update_part_data(part)\n00722| -- NOTE: This isn't the first time we've seen the part but we haven't rendered it previously\n00723| -- so try and render it this time by setting is_new_part = true (otherwise we'd call\n00724| -- _replace_message_in_buffer and it wouldn't do anything because the part hasn't been rendered)\n00725| if not rendered_part or (not rendered_part.line_start and not rendered_part.line_end) then\n00726| is_new_part = true\n00727| end\n00728| end\n00729| \n00730| local formatted = formatter.format_part(part, message, is_last_part)\n00731| \n00732| if revert_index and is_new_part then\n00733| return\n00734| end\n00735| \n00736| if is_new_part then\n00737| M._insert_part_to_buffer(part.id, formatted)\n00738| \n00739| if message.info.error then\n00740| --- NOTE: More error display code. As mentioned above, errors come in on messages\n00741| --- but we want to display them after parts so we tack the error onto the last\n00742| --- part. When a part is added and there's an error, we need to rerender\n00743| --- previous last part so it doesn't also display the message. If there was no previous\n00744| --- part, then we need to rerender the header so it doesn't display the error\n00745| \n00746| if not prev_last_part_id then\n00747| -- no previous part, we're the first part, re-render the message header\n00748| -- so it doesn't also display the error\n00749| local header_data = formatter.format_message_header(message)\n00750| M._replace_message_in_buffer(part.messageID, header_data)\n00751| elseif prev_last_part_id ~= part.id then\n00752| M._rerender_part(prev_last_part_id)\n00753| end\n00754| end\n00755| else\n00756| M._replace_part_in_buffer(part.id, formatted)\n00757| end\n00758| \n00759| if (part.type == 'file' or part.type == 'agent') and part.source then\n00760| -- we have a mention, we need to rerender the early part to highlight\n00761| -- the mention.\n00762| local text_part_id = M._find_text_part_for_message(message)\n00763| if text_part_id then\n00764| M._rerender_part(text_part_id)\n00765| end\n00766| end\n00767| end\n00768| \n00769| ---Event handler for message.part.removed events\n00770| ---@param properties {sessionID: string, messageID: string, partID: string} Event properties\n00771| function M.on_part_removed(properties)\n00772| if not properties then\n00773| return\n00774| end\n00775| \n00776| local part_id = properties.partID\n00777| if not part_id then\n00778| return\n00779| end\n00780| \n00781| local cached = M._render_state:get_part(part_id)\n00782| if cached and cached.message_id then\n00783| local rendered_message = M._render_state:get_message(cached.message_id)\n00784| if rendered_message and rendered_message.message then\n00785| local message = rendered_message.message\n00786| if message.parts then\n00787| for i, part in ipairs(message.parts) do\n00788| if part.id == part_id then\n00789| table.remove(message.parts, i)\n00790| break\n00791| end\n00792| end\n00793| end\n00794| end\n00795| end\n00796| \n00797| M._remove_part_from_buffer(part_id)\n00798| end\n00799| \n00800| ---Event handler for message.removed events\n00801| ---Removes message and all its parts from buffer\n00802| ---@param properties {sessionID: string, messageID: string} Event properties\n00803| function M.on_message_removed(properties)\n00804| if not properties or not state.messages then\n00805| return\n00806| end\n00807| \n00808| local message_id = properties.messageID\n00809| if not message_id then\n00810| return\n00811| end\n00812| \n00813| local rendered_message = M._render_state:get_message(message_id)\n00814| if not rendered_message or not rendered_message.message then\n00815| return\n00816| end\n00817| \n00818| local message = rendered_message.message\n00819| for _, part in ipairs(message.parts or {}) do\n00820| if part.id then\n00821| M._remove_part_from_buffer(part.id)\n00822| end\n00823| end\n00824| \n00825| M._remove_message_from_buffer(message_id)\n00826| \n00827| for i, msg in ipairs(state.messages or {}) do\n00828| if msg.info.id == message_id then\n00829| table.remove(state.messages, i)\n00830| break\n00831| end\n00832| end\n00833| end\n00834| \n00835| ---Event handler for session.compacted events\n00836| ---@param properties {sessionID: string} Event properties\n00837| function M.on_session_compacted(properties)\n00838| vim.notify('Session has been compacted')\n00839| end\n00840| \n00841| ---Event handler for session.updated events\n00842| ---@param properties {info: Session}\n00843| function M.on_session_updated(properties)\n00844| if not properties or not properties.info or not state.active_session then\n00845| return\n00846| end\n00847| if not vim.deep_equal(state.active_session.revert, properties.info.revert) then\n00848| state.active_session.revert = properties.info.revert\n00849| M._render_full_session_data(state.messages)\n00850| end\n00851| end\n00852| \n00853| ---Event handler for session.error events\n00854| ---@param properties {sessionID: string, error: table} Event properties\n00855| function M.on_session_error(properties)\n00856| if not properties or not properties.error then\n00857| return\n00858| end\n00859| \n00860| -- NOTE: we're handling message errors so session errors seem duplicative\n00861| if config.debug.enabled then\n00862| vim.notify('Session error: ' .. vim.inspect(properties.error))\n00863| end\n00864| end\n00865| \n00866| ---Event handler for permission.updated events\n00867| ---Re-renders part that requires permission and adds to permission window\n00868| ---@param permission OpencodePermission Event properties\n00869| function M.on_permission_updated(permission)\n00870| local tool = permission.tool\n00871| \n00872| ---@TODO this is for backward compatibility, remove later\n00873| local callID = tool and tool.callID or permission.callID\n00874| local messageID = tool and tool.messageID or permission.messageID\n00875| \n00876| if not permission or not messageID or not callID then\n00877| return\n00878| end\n00879| \n00880| -- Add permission to pending queue\n00881| if not state.pending_permissions then\n00882| state.pending_permissions = {}\n00883| end\n00884| \n00885| -- Check if permission already exists in queue\n00886| local existing_index = nil\n00887| for i, existing in ipairs(state.pending_permissions) do\n00888| if existing.id == permission.id then\n00889| existing_index = i\n00890| break\n00891| end\n00892| end\n00893| \n00894| local permissions = vim.deepcopy(state.pending_permissions)\n00895| if existing_index then\n00896| permissions[existing_index] = permission\n00897| else\n00898| table.insert(permissions, permission)\n00899| end\n00900| state.pending_permissions = permissions\n00901| \n00902| permission_window.add_permission(permission)\n00903| \n00904| M.render_permissions_display()\n00905| \n00906| M._rerender_part('permission-display-part')\n00907| M.scroll_to_bottom()\n00908| end\n00909| \n00910| ---Event handler for permission.replied events\n00911| ---Re-renders part after permission is resolved and removes from window\n00912| ---@param properties {sessionID: string, permissionID?: string,requestID?: string, response: string}|{} Event properties\n00913| function M.on_permission_replied(properties)\n00914| if not properties then\n00915| return\n00916| end\n00917| \n00918| local permission_id = properties.permissionID or properties.requestID\n00919| \n00920| if permission_id then\n00921| permission_window.remove_permission(permission_id)\n00922| state.pending_permissions = vim.deepcopy(permission_window.get_all_permissions())\n00923| if #state.pending_permissions == 0 then\n00924| M._remove_part_from_buffer('permission-display-part')\n00925| M._remove_message_from_buffer('permission-display-message')\n00926| end\n00927| M._rerender_part('permission-display-part')\n00928| end\n00929| end\n00930| \n00931| ---Event handler for question.asked events\n00932| ---Shows the question picker UI for the user to answer\n00933| ---@param properties OpencodeQuestionRequest Event properties\n00934| function M.on_question_asked(properties)\n00935| if not properties or not properties.id or not properties.questions then\n00936| return\n00937| end\n00938| \n00939| if not state.active_session or properties.sessionID ~= state.active_session.id then\n00940| return\n00941| end\n00942| \n00943| local question_window = require('opencode.ui.question_window')\n00944| question_window.show_question(properties)\n00945| end\n00946| \n00947| function M.on_file_edited(properties)\n00948| vim.cmd('checktime')\n00949| if config.hooks and config.hooks.on_file_edited then\n00950| pcall(config.hooks.on_file_edited, properties.file)\n00951| end\n00952| end\n00953| \n00954| ---@param properties RestorePointCreatedEvent\n00955| function M.on_restore_points(properties)\n00956| state.append('restore_points', properties.restore_point)\n00957| if not properties or not properties.restore_point or not properties.restore_point.from_snapshot_id then\n00958| return\n00959| end\n00960| local part = M._render_state:get_part_by_snapshot_id(properties.restore_point.from_snapshot_id)\n00961| if part then\n00962| M.on_part_updated({ part = part })\n00963| end\n00964| end\n00965| \n00966| ---Find part ID by call ID and message ID\n00967| ---Useful for finding a part for a permission\n00968| ---@param call_id string Call ID to search for\n00969| ---@param message_id string Message ID to check the parts of\n00970| ---@return string? part_id Part ID if found, nil otherwise\n00971| function M._find_part_by_call_id(call_id, message_id)\n00972| return M._render_state:get_part_by_call_id(call_id, message_id)\n00973| end\n00974| \n00975| ---Find the text part in a message\n00976| ---@param message OpencodeMessage The message containing the parts\n00977| ---@return string? text_part_id The ID of the text part\n00978| function M._find_text_part_for_message(message)\n00979| if not message or not message.parts then\n00980| return nil\n00981| end\n00982| \n00983| for _, part in ipairs(message.parts) do\n00984| if part.type == 'text' and not part.synthetic then\n00985| return part.id\n00986| end\n00987| end\n00988| \n00989| return nil\n00990| end\n00991| \n00992| ---Find the last part in a message\n00993| ---@param message OpencodeMessage The message containing the parts\n00994| ---@return string? last_part_id The ID of the last part\n00995| function M._get_last_part_for_message(message)\n00996| if not message or not message.parts or #message.parts == 0 then\n00997| return nil\n00998| end\n00999| \n01000| for i = #message.parts, 1, -1 do\n01001| local part = message.parts[i]\n01002| if part.type ~= 'step-start' and part.type ~= 'step-finish' and part.id then\n01003| return part.id\n01004| end\n01005| end\n01006| \n01007| return nil\n01008| end\n01009| \n01010| ---Get insertion point for an out-of-order part\n01011| ---@param part_id string The part ID to insert\n01012| ---@param message_id string The message ID the part belongs to\n01013| ---@return integer? insertion_line The line to insert at (1-indexed), or nil on error\n01014| function M._get_insertion_point_for_part(part_id, message_id)\n01015| local rendered_message = M._render_state:get_message(message_id)\n01016| if not rendered_message or not rendered_message.message then\n01017| return nil\n01018| end\n01019| \n01020| local message = rendered_message.message\n01021| \n01022| local insertion_line = rendered_message.line_end and (rendered_message.line_end + 1)\n01023| if not insertion_line then\n01024| return nil\n01025| end\n01026| \n01027| local current_part_index = nil\n01028| if message.parts then\n01029| for i, part in ipairs(message.parts) do\n01030| if part.id == part_id then\n01031| current_part_index = i\n01032| break\n01033| end\n01034| end\n01035| end\n01036| \n01037| if not current_part_index then\n01038| return insertion_line\n01039| end\n01040| \n01041| for i = current_part_index - 1, 1, -1 do\n01042| local prev_part = message.parts[i]\n01043| if prev_part and prev_part.id then\n01044| local prev_rendered = M._render_state:get_part(prev_part.id)\n01045| \n01046| if prev_rendered and prev_rendered.line_end then\n01047| return prev_rendered.line_end + 1\n01048| end\n01049| end\n01050| end\n01051| \n01052| return insertion_line\n01053| end\n01054| \n01055| ---Re-render existing part with current state\n01056| ---Used for permission updates and other dynamic changes\n01057| ---@param part_id string Part ID to re-render\n01058| function M._rerender_part(part_id)\n01059| local cached = M._render_state:get_part(part_id)\n01060| if not cached or not cached.part then\n01061| return\n01062| end\n01063| \n01064| local part = cached.part\n01065| local rendered_message = M._render_state:get_message(cached.message_id)\n01066| if not rendered_message or not rendered_message.message then\n01067| return\n01068| end\n01069| \n01070| local message = rendered_message.message\n01071| local last_part_id = M._get_last_part_for_message(message)\n01072| local is_last_part = (last_part_id == part_id)\n01073| local formatted = formatter.format_part(part, message, is_last_part)\n01074| \n01075| M._replace_part_in_buffer(part_id, formatted)\n01076| end\n01077| \n01078| ---Event handler for focus changes\n01079| ---Re-renders part associated with current permission for displaying global shortcuts or buffer-local ones\n01080| function M.on_focus_changed()\n01081| -- Check permission window first, fallback to state\n01082| local current_permission = permission_window.get_all_permissions()[1]\n01083| \n01084| if not current_permission then\n01085| return\n01086| end\n01087| \n01088| M._rerender_part('permission-display-part')\n01089| trigger_on_data_rendered()\n01090| end\n01091| \n01092| function M.on_session_changed(_, new, _)\n01093| M.reset()\n01094| if new then\n01095| M.render_full_session()\n01096| end\n01097| end\n01098| \n01099| ---Get all actions available at a specific line\n01100| ---@param line integer 0-indexed line number\n01101| ---@return table[] List of actions available at that line\n01102| function M.get_actions_for_line(line)\n01103| return M._render_state:get_actions_at_line(line)\n01104| end\n01105| \n01106| ---Update display stats from a single message\n01107| ---@param message OpencodeMessage\n01108| function M._update_stats_from_message(message)\n01109| if not state.current_model and message.info.providerID and message.info.providerID ~= '' then\n01110| state.current_model = message.info.providerID .. '/' .. message.info.modelID\n01111| end\n01112| \n01113| local tokens = message.info.tokens\n01114| if tokens and tokens.input > 0 then\n01115| state.tokens_count = tokens.input + tokens.output + tokens.cache.read + tokens.cache.write\n01116| end\n01117| \n01118| if message.info.cost and type(message.info.cost) == 'number' then\n01119| state.cost = message.info.cost\n01120| end\n01121| end\n01122| \n01123| ---Get rendered message by ID\n01124| ---@param message_id string Message ID\n01125| ---@return RenderedMessage|nil Rendered message or nil if not found\n01126| function M.get_rendered_message(message_id)\n01127| local rendered_msg = M._render_state:get_message(message_id)\n01128| if rendered_msg then\n01129| return rendered_msg\n01130| end\n01131| return nil\n01132| end\n01133| \n01134| return M\n01135| \n\n(End of file - total 1135 lines)\n","type":"text","id":"prt_bfaa078ae001zhO39Uz3en7btW"}}},{"type":"message.part.updated","properties":{"part":{"filename":"lua/opencode/ui/renderer.lua","messageID":"msg_bfaa078a2001RUYhlKZhSlyWeF","type":"file","id":"prt_bfaa078ae002XvKak6z08HB5LV","url":"file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/renderer.lua","mime":"text/plain","sessionID":"ses_4055f967bffeIHf3DnP0xntmxD"}}},{"type":"message.part.updated","properties":{"part":{"messageID":"msg_bfaa078a2001RUYhlKZhSlyWeF","text":"can you use the question tool and ask me a question with an other choice","id":"prt_bfaa078a4001OxXpwZJxaFmqUo","type":"text","sessionID":"ses_4055f967bffeIHf3DnP0xntmxD"}}},{"type":"session.updated","properties":{"info":{"directory":"/home/francis/Projects/_nvim/opencode.nvim","version":"1.1.31","slug":"calm-lagoon","id":"ses_4055f967bffeIHf3DnP0xntmxD","title":"New session - 2026-01-26T14:06:15.428Z","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","time":{"created":1769436375428,"updated":1769436379349}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"modelID":"gpt-4.1","providerID":"github-copilot","id":"msg_bfaa078e7001qc33BqBlqzHv8X","agent":"build","mode":"build","tokens":{"reasoning":0,"input":0,"cache":{"read":0,"write":0},"output":0},"parentID":"msg_bfaa078a2001RUYhlKZhSlyWeF","sessionID":"ses_4055f967bffeIHf3DnP0xntmxD","role":"assistant","cost":0,"time":{"created":1769436379367}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"time":{"created":1769436379298},"id":"msg_bfaa078a2001RUYhlKZhSlyWeF","agent":"build","sessionID":"ses_4055f967bffeIHf3DnP0xntmxD","role":"user","model":{"modelID":"gpt-4.1","providerID":"github-copilot"},"summary":{"diffs":[]}}}},{"type":"session.updated","properties":{"info":{"directory":"/home/francis/Projects/_nvim/opencode.nvim","version":"1.1.31","title":"New session - 2026-01-26T14:06:15.428Z","slug":"calm-lagoon","id":"ses_4055f967bffeIHf3DnP0xntmxD","time":{"created":1769436375428,"updated":1769436379539},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","summary":{"deletions":0,"files":0,"additions":0}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"messageID":"msg_bfaa078e7001qc33BqBlqzHv8X","id":"prt_bfaa07ecf0011yakDSUtAyStvx","sessionID":"ses_4055f967bffeIHf3DnP0xntmxD","type":"step-start","snapshot":"56238d5c6bb499e9e265444377a201fba6b1a880"}}},{"type":"message.part.updated","properties":{"part":{"id":"prt_bfaa07ed3001RYplcvPxb660OT","type":"tool","tool":"question","state":{"raw":"","status":"pending","input":{}},"sessionID":"ses_4055f967bffeIHf3DnP0xntmxD","messageID":"msg_bfaa078e7001qc33BqBlqzHv8X","callID":"call_IpPBuTk1riUXZDmDUDghZEpB"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"question.asked","properties":{"id":"que_bfaa0833a001jKE5x0BCsGLOYX","sessionID":"ses_4055f967bffeIHf3DnP0xntmxD","questions":[{"header":"Favorite color","question":"What is your favorite color?","options":[{"label":"Red","description":"The color red"},{"label":"Blue","description":"The color blue"},{"label":"Other","description":"Any color not listed"}]}],"tool":{"messageID":"msg_bfaa078e7001qc33BqBlqzHv8X","callID":"call_IpPBuTk1riUXZDmDUDghZEpB"}}},{"type":"message.part.updated","properties":{"part":{"id":"prt_bfaa07ed3001RYplcvPxb660OT","type":"tool","tool":"question","state":{"status":"running","input":{"questions":[{"header":"Favorite color","question":"What is your favorite color?","options":[{"label":"Red","description":"The color red"},{"label":"Blue","description":"The color blue"},{"label":"Other","description":"Any color not listed"}]}]},"time":{"start":1769436382010}},"sessionID":"ses_4055f967bffeIHf3DnP0xntmxD","messageID":"msg_bfaa078e7001qc33BqBlqzHv8X","callID":"call_IpPBuTk1riUXZDmDUDghZEpB"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"time":{"created":1769436379298},"id":"msg_bfaa078a2001RUYhlKZhSlyWeF","agent":"build","sessionID":"ses_4055f967bffeIHf3DnP0xntmxD","role":"user","model":{"modelID":"gpt-4.1","providerID":"github-copilot"},"summary":{"diffs":[],"title":"Question including Other option"}}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"session.updated","properties":{"info":{"directory":"/home/francis/Projects/_nvim/opencode.nvim","version":"1.1.31","title":"Question about opencode/ui/renderer.lua","slug":"calm-lagoon","id":"ses_4055f967bffeIHf3DnP0xntmxD","time":{"created":1769436375428,"updated":1769436379539},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","summary":{"deletions":0,"files":0,"additions":0}}}},{"type":"custom.emit_events.finished","properties":[]}]
+[
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "version": "1.1.31",
+ "slug": "calm-lagoon",
+ "id": "ses_4055f967bffeIHf3DnP0xntmxD",
+ "title": "New session - 2026-01-26T14:06:15.428Z",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "time": { "created": 1769436375428, "updated": 1769436375428 }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "time": { "created": 1769436379298 },
+ "id": "msg_bfaa078a2001RUYhlKZhSlyWeF",
+ "sessionID": "ses_4055f967bffeIHf3DnP0xntmxD",
+ "role": "user",
+ "model": { "modelID": "gpt-4.1", "providerID": "github-copilot" },
+ "agent": "build"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "synthetic": true,
+ "messageID": "msg_bfaa078a2001RUYhlKZhSlyWeF",
+ "sessionID": "ses_4055f967bffeIHf3DnP0xntmxD",
+ "text": "Called the Read tool with the following input: {\"filePath\":\"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/renderer.lua\"}",
+ "type": "text",
+ "id": "prt_bfaa078a5001Pni4eaodfXL6o6"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "synthetic": true,
+ "messageID": "msg_bfaa078a2001RUYhlKZhSlyWeF",
+ "sessionID": "ses_4055f967bffeIHf3DnP0xntmxD",
+ "text": "\n00001| local state = require('opencode.state')\n00002| local config = require('opencode.config')\n00003| local formatter = require('opencode.ui.formatter')\n00004| local output_window = require('opencode.ui.output_window')\n00005| local permission_window = require('opencode.ui.permission_window')\n00006| local Promise = require('opencode.promise')\n00007| local RenderState = require('opencode.ui.render_state')\n00008| \n00009| local M = {\n00010| _prev_line_count = 0,\n00011| _render_state = RenderState.new(),\n00012| _last_part_formatted = {\n00013| part_id = nil,\n00014| formatted_data = nil --[[@as Output|nil]],\n00015| },\n00016| }\n00017| \n00018| local trigger_on_data_rendered = require('opencode.util').debounce(function()\n00019| local cb_type = type(config.ui.output.rendering.on_data_rendered)\n00020| \n00021| if cb_type == 'boolean' then\n00022| return\n00023| end\n00024| \n00025| if not state.windows or not state.windows.output_buf or not state.windows.output_win then\n00026| return\n00027| end\n00028| \n00029| if cb_type == 'function' then\n00030| pcall(config.ui.output.rendering.on_data_rendered, state.windows.output_buf, state.windows.output_win)\n00031| elseif vim.fn.exists(':RenderMarkdown') > 0 then\n00032| vim.cmd(':RenderMarkdown')\n00033| elseif vim.fn.exists(':Markview') > 0 then\n00034| vim.cmd(':Markview render ' .. state.windows.output_buf)\n00035| end\n00036| end, config.ui.output.rendering.markdown_debounce_ms or 250)\n00037| \n00038| ---Reset renderer state\n00039| function M.reset()\n00040| M._prev_line_count = 0\n00041| M._render_state:reset()\n00042| M._last_part_formatted = { part_id = nil, formatted_data = nil }\n00043| \n00044| output_window.clear()\n00045| \n00046| state.messages = {}\n00047| state.last_user_message = nil\n00048| state.tokens_count = 0\n00049| \n00050| local permissions = state.pending_permissions or {}\n00051| if #permissions and state.api_client then\n00052| for _, permission in ipairs(permissions) do\n00053| require('opencode.api').permission_deny(permission)\n00054| end\n00055| end\n00056| permission_window.clear_all()\n00057| state.pending_permissions = {}\n00058| \n00059| trigger_on_data_rendered()\n00060| end\n00061| \n00062| ---Set up event subscriptions\n00063| ---@param subscribe? boolean false to unsubscribe\n00064| function M.setup_subscriptions(subscribe)\n00065| subscribe = subscribe == nil and true or subscribe\n00066| \n00067| if subscribe then\n00068| state.subscribe('is_opencode_focused', M.on_focus_changed)\n00069| state.subscribe('active_session', M.on_session_changed)\n00070| else\n00071| state.unsubscribe('is_opencode_focused', M.on_focus_changed)\n00072| state.unsubscribe('active_session', M.on_session_changed)\n00073| end\n00074| \n00075| if not state.event_manager then\n00076| return\n00077| end\n00078| \n00079| local event_subscriptions = {\n00080| { 'session.updated', M.on_session_updated },\n00081| { 'session.compacted', M.on_session_compacted },\n00082| { 'session.error', M.on_session_error },\n00083| { 'message.updated', M.on_message_updated },\n00084| { 'message.removed', M.on_message_removed },\n00085| { 'message.part.updated', M.on_part_updated },\n00086| { 'message.part.removed', M.on_part_removed },\n00087| { 'permission.updated', M.on_permission_updated },\n00088| { 'permission.asked', M.on_permission_updated },\n00089| { 'permission.replied', M.on_permission_replied },\n00090| { 'question.asked', M.on_question_asked },\n00091| { 'question.replied', M.clear_question_display },\n00092| { 'question.rejected', M.clear_question_display },\n00093| { 'file.edited', M.on_file_edited },\n00094| { 'custom.restore_point.created', M.on_restore_points },\n00095| { 'custom.emit_events.finished', M.on_emit_events_finished },\n00096| }\n00097| \n00098| for _, sub in ipairs(event_subscriptions) do\n00099| if subscribe then\n00100| state.event_manager:subscribe(sub[1], sub[2])\n00101| else\n00102| state.event_manager:unsubscribe(sub[1], sub[2])\n00103| end\n00104| end\n00105| end\n00106| \n00107| ---Clean up and teardown renderer. Unsubscribes from all events\n00108| function M.teardown()\n00109| M.setup_subscriptions(false)\n00110| M.reset()\n00111| end\n00112| \n00113| ---Fetch full session messages from server\n00114| ---@return Promise Promise resolving to list of OpencodeMessage\n00115| local function fetch_session()\n00116| local session = state.active_session\n00117| if not session or not session or session == '' then\n00118| return Promise.new():resolve(nil)\n00119| end\n00120| \n00121| state.last_user_message = nil\n00122| return require('opencode.session').get_messages(session)\n00123| end\n00124| \n00125| ---Request all of the session data from the opencode server and render it\n00126| ---@return Promise\n00127| function M.render_full_session()\n00128| if not output_window.mounted() or not state.api_client then\n00129| return Promise.new():resolve(nil)\n00130| end\n00131| \n00132| return fetch_session():and_then(M._render_full_session_data)\n00133| end\n00134| \n00135| function M._render_full_session_data(session_data)\n00136| M.reset()\n00137| \n00138| if not state.active_session or not state.messages then\n00139| return\n00140| end\n00141| \n00142| local revert_index = nil\n00143| \n00144| -- if we're loading a session and there's no currently selected model, set it\n00145| -- from the messages\n00146| local set_mode_from_messages = not state.current_model\n00147| \n00148| for i, msg in ipairs(session_data) do\n00149| if state.active_session.revert and state.active_session.revert.messageID == msg.info.id then\n00150| revert_index = i\n00151| end\n00152| \n00153| M.on_message_updated({ info = msg.info }, revert_index)\n00154| \n00155| for _, part in ipairs(msg.parts or {}) do\n00156| M.on_part_updated({ part = part }, revert_index)\n00157| end\n00158| end\n00159| \n00160| if revert_index then\n00161| M._write_formatted_data(formatter._format_revert_message(state.messages, revert_index))\n00162| end\n00163| \n00164| if set_mode_from_messages then\n00165| M._set_model_and_mode_from_messages()\n00166| end\n00167| M.scroll_to_bottom()\n00168| \n00169| if config.hooks and config.hooks.on_session_loaded then\n00170| pcall(config.hooks.on_session_loaded, state.active_session)\n00171| end\n00172| end\n00173| \n00174| ---Append permissions display as a fake part at the end\n00175| function M.render_permissions_display()\n00176| local fake_message = {\n00177| info = {\n00178| id = 'permission-display-message',\n00179| sessionID = state.active_session and state.active_session.id or '',\n00180| role = 'system',\n00181| },\n00182| parts = {},\n00183| }\n00184| M.on_message_updated(fake_message)\n00185| \n00186| local fake_part = {\n00187| id = 'permission-display-part',\n00188| messageID = 'permission-display-message',\n00189| sessionID = state.active_session and state.active_session.id or '',\n00190| type = 'permissions-display',\n00191| }\n00192| \n00193| local permissions = permission_window.get_all_permissions()\n00194| if #permissions > 0 then\n00195| M.on_part_updated({ part = fake_part })\n00196| end\n00197| end\n00198| \n00199| function M.clear_question_display()\n00200| local question_window = require('opencode.ui.question_window')\n00201| question_window.clear_question()\n00202| M._remove_part_from_buffer('question-display-part')\n00203| M._remove_message_from_buffer('question-display-message')\n00204| end\n00205| \n00206| ---Render question display as a fake part\n00207| function M.render_question_display()\n00208| local question_window = require('opencode.ui.question_window')\n00209| \n00210| local current_question = question_window._current_question\n00211| \n00212| if not question_window.has_question() or not current_question or not current_question.id then\n00213| M._remove_part_from_buffer('question-display-part')\n00214| M._remove_message_from_buffer('question-display-message')\n00215| return\n00216| end\n00217| \n00218| local message_id = 'question-display-message'\n00219| local part_id = 'question-display-part'\n00220| \n00221| local fake_message = {\n00222| info = {\n00223| id = message_id,\n00224| sessionID = state.active_session and state.active_session.id or '',\n00225| role = 'system',\n00226| },\n00227| parts = {},\n00228| }\n00229| M.on_message_updated(fake_message)\n00230| \n00231| local fake_part = {\n00232| id = part_id,\n00233| messageID = message_id,\n00234| sessionID = state.active_session and state.active_session.id or '',\n00235| type = 'questions-display',\n00236| }\n00237| \n00238| M.on_part_updated({ part = fake_part })\n00239| M._redraw()\n00240| M.scroll_to_bottom(true)\n00241| end\n00242| \n00243| function M._redraw()\n00244| if state.windows and state.windows.output_win and vim.api.nvim_win_is_valid(state.windows.output_win) then\n00245| vim.api.nvim_win_call(state.windows.output_win, function()\n00246| vim.cmd('redraw')\n00247| end)\n00248| end\n00249| end\n00250| \n00251| ---Render lines as the entire output buffer\n00252| ---@param lines any\n00253| function M.render_lines(lines)\n00254| local output = require('opencode.ui.output'):new()\n00255| output.lines = lines\n00256| M.render_output(output)\n00257| end\n00258| \n00259| ---Sets the entire output buffer based on output_data\n00260| ---@param output_data Output Output object from formatter\n00261| function M.render_output(output_data)\n00262| if not output_window.mounted() then\n00263| return\n00264| end\n00265| \n00266| local lines = output_data.lines or {}\n00267| \n00268| output_window.set_lines(lines)\n00269| output_window.clear_extmarks()\n00270| output_window.set_extmarks(output_data.extmarks)\n00271| M.scroll_to_bottom()\n00272| end\n00273| \n00274| ---Called when EventManager has finished emitting a batch of events\n00275| function M.on_emit_events_finished()\n00276| M.scroll_to_bottom()\n00277| end\n00278| \n00279| ---Find the most recently used model from the messages\n00280| function M._set_model_and_mode_from_messages()\n00281| if not state.messages then\n00282| return\n00283| end\n00284| \n00285| for i = #state.messages, 1, -1 do\n00286| local message = state.messages[i]\n00287| \n00288| if message and message.info then\n00289| if message.info.modelID and message.info.providerID then\n00290| state.current_model = message.info.providerID .. '/' .. message.info.modelID\n00291| if message.info.mode then\n00292| state.current_mode = message.info.mode\n00293| end\n00294| return\n00295| end\n00296| end\n00297| end\n00298| \n00299| -- we didn't find a model from any messages, set it to the default\n00300| require('opencode.core').initialize_current_model()\n00301| end\n00302| \n00303| ---Auto-scroll to bottom if user was already at bottom\n00304| ---Respects cursor position if user has scrolled up\n00305| ---@param force? boolean If true, scroll regardless of current position\n00306| function M.scroll_to_bottom(force)\n00307| if not state.windows or not state.windows.output_buf or not state.windows.output_win then\n00308| return\n00309| end\n00310| \n00311| if not vim.api.nvim_win_is_valid(state.windows.output_win) then\n00312| return\n00313| end\n00314| \n00315| local ok, line_count = pcall(vim.api.nvim_buf_line_count, state.windows.output_buf)\n00316| if not ok or line_count == 0 then\n00317| return\n00318| end\n00319| \n00320| local prev_line_count = M._prev_line_count or 0\n00321| \n00322| ---@cast line_count integer\n00323| M._prev_line_count = line_count\n00324| \n00325| trigger_on_data_rendered()\n00326| \n00327| -- Determine if we should scroll to bottom\n00328| local should_scroll = force == true\n00329| \n00330| if not should_scroll then\n00331| -- Always scroll on initial render\n00332| if prev_line_count == 0 then\n00333| should_scroll = true\n00334| -- Scroll if user is at bottom (respects manual scroll position)\n00335| elseif output_window.viewport_at_bottom then\n00336| should_scroll = true\n00337| end\n00338| end\n00339| \n00340| if should_scroll then\n00341| vim.api.nvim_win_set_cursor(state.windows.output_win, { line_count, 0 })\n00342| -- Use zb to position the cursor line at the bottom of the visible window\n00343| vim.api.nvim_win_call(state.windows.output_win, function()\n00344| vim.cmd('normal! zb')\n00345| end)\n00346| output_window.viewport_at_bottom = true\n00347| else\n00348| -- User has scrolled up, don't scroll\n00349| output_window.viewport_at_bottom = false\n00350| end\n00351| end\n00352| \n00353| ---Write data to output_buf, including normal text and extmarks\n00354| ---@param formatted_data Output Formatted data as Output object\n00355| ---@param part_id? string Optional part ID to store actions\n00356| ---@param start_line? integer Optional line to insert at (shifts content down). If nil, appends to end of buffer.\n00357| ---@return {line_start: integer, line_end: integer}? Range where data was written\n00358| function M._write_formatted_data(formatted_data, part_id, start_line)\n00359| if not state.windows or not state.windows.output_buf then\n00360| return\n00361| end\n00362| \n00363| local buf = state.windows.output_buf\n00364| local is_insertion = start_line ~= nil\n00365| local target_line = start_line or output_window.get_buf_line_count()\n00366| local new_lines = formatted_data.lines\n00367| local extmarks = formatted_data.extmarks\n00368| \n00369| if #new_lines == 0 or not buf then\n00370| return nil\n00371| end\n00372| \n00373| if is_insertion then\n00374| output_window.set_lines(new_lines, target_line, target_line)\n00375| else\n00376| local extra_newline = vim.tbl_extend('keep', {}, new_lines)\n00377| table.insert(extra_newline, '')\n00378| target_line = target_line - 1\n00379| output_window.set_lines(extra_newline, target_line)\n00380| end\n00381| \n00382| -- update actions and extmarks after the insertion because that may\n00383| -- adjust target_line (e.g. when we we're replacing the double newline at\n00384| -- the end)\n00385| \n00386| if part_id and formatted_data.actions then\n00387| M._render_state:add_actions(part_id, formatted_data.actions, target_line)\n00388| end\n00389| \n00390| output_window.set_extmarks(extmarks, target_line)\n00391| \n00392| return {\n00393| line_start = target_line,\n00394| line_end = target_line + #new_lines - 1,\n00395| }\n00396| end\n00397| \n00398| ---Insert new part, either at end of buffer or in the middle for out-of-order parts\n00399| ---@param part_id string Part ID\n00400| ---@param formatted_data Output Formatted data as Output object\n00401| ---@return boolean Success status\n00402| function M._insert_part_to_buffer(part_id, formatted_data)\n00403| local cached = M._render_state:get_part(part_id)\n00404| if not cached then\n00405| return false\n00406| end\n00407| \n00408| if #formatted_data.lines == 0 then\n00409| return true\n00410| end\n00411| \n00412| local is_current_message = state.current_message\n00413| and state.current_message.info\n00414| and state.current_message.info.id == cached.message_id\n00415| \n00416| if is_current_message then\n00417| -- NOTE: we're inserting a part for the current message, just add it to the end\n00418| \n00419| local range = M._write_formatted_data(formatted_data, part_id)\n00420| if not range then\n00421| return false\n00422| end\n00423| \n00424| M._render_state:set_part(cached.part, range.line_start, range.line_end)\n00425| \n00426| M._last_part_formatted = { part_id = part_id, formatted_data = formatted_data }\n00427| \n00428| return true\n00429| end\n00430| \n00431| -- NOTE: We're inserting a part for the first time for a previous message. We need to find\n00432| -- the insertion line (after the last part of this message or after the message header if\n00433| -- no parts).\n00434| local insertion_line = M._get_insertion_point_for_part(part_id, cached.message_id)\n00435| if not insertion_line then\n00436| return false\n00437| end\n00438| \n00439| local range = M._write_formatted_data(formatted_data, part_id, insertion_line)\n00440| if not range then\n00441| return false\n00442| end\n00443| \n00444| local line_count = #formatted_data.lines\n00445| M._render_state:shift_all(insertion_line, line_count)\n00446| \n00447| M._render_state:set_part(cached.part, range.line_start, range.line_end)\n00448| \n00449| return true\n00450| end\n00451| \n00452| ---Replace existing part in buffer\n00453| ---Adjusts line positions of subsequent parts if line count changes\n00454| ---@param part_id string Part ID\n00455| ---@param formatted_data Output Formatted data as Output object\n00456| ---@return boolean Success status\n00457| function M._replace_part_in_buffer(part_id, formatted_data)\n00458| local cached = M._render_state:get_part(part_id)\n00459| if not cached or not cached.line_start or not cached.line_end then\n00460| return false\n00461| end\n00462| \n00463| local new_lines = formatted_data.lines\n00464| local new_line_count = #new_lines\n00465| \n00466| local old_formatted = M._last_part_formatted\n00467| local can_optimize = old_formatted\n00468| and old_formatted.part_id == part_id\n00469| and old_formatted.formatted_data\n00470| and old_formatted.formatted_data.lines\n00471| \n00472| local lines_to_write = new_lines\n00473| local write_start_line = cached.line_start\n00474| \n00475| if can_optimize then\n00476| -- NOTE: This is an optimization to only replace the lines that are different\n00477| -- if we're replacing the most recently formatted part.\n00478| \n00479| ---@cast old_formatted { formatted_data: { lines: string[] } }\n00480| local old_lines = old_formatted.formatted_data.lines\n00481| local first_diff_line = nil\n00482| \n00483| -- Find the first line that's different\n00484| for i = 1, math.min(#old_lines, new_line_count) do\n00485| if old_lines[i] ~= new_lines[i] then\n00486| first_diff_line = i\n00487| break\n00488| end\n00489| end\n00490| \n00491| if not first_diff_line and new_line_count > #old_lines then\n00492| -- The old lines all matched but maybe there are more new lines\n00493| first_diff_line = #old_lines + 1\n00494| end\n00495| \n00496| if first_diff_line then\n00497| lines_to_write = vim.list_slice(new_lines, first_diff_line, new_line_count)\n00498| write_start_line = cached.line_start + first_diff_line - 1\n00499| elseif new_line_count == #old_lines then\n00500| -- Nothing was different, so we're done\n00501| M._last_part_formatted = { part_id = part_id, formatted_data = formatted_data }\n00502| return true\n00503| end\n00504| end\n00505| \n00506| M._render_state:clear_actions(part_id)\n00507| \n00508| output_window.clear_extmarks(cached.line_start - 1, cached.line_end + 1)\n00509| output_window.set_lines(lines_to_write, write_start_line, cached.line_end + 1)\n00510| \n00511| local new_line_end = cached.line_start + new_line_count - 1\n00512| \n00513| output_window.set_extmarks(formatted_data.extmarks, cached.line_start)\n00514| \n00515| if formatted_data.actions then\n00516| M._render_state:add_actions(part_id, formatted_data.actions, cached.line_start + 1)\n00517| end\n00518| \n00519| M._render_state:update_part_lines(part_id, cached.line_start, new_line_end)\n00520| \n00521| M._last_part_formatted = { part_id = part_id, formatted_data = formatted_data }\n00522| \n00523| return true\n00524| end\n00525| \n00526| ---Remove part from buffer and adjust subsequent line positions\n00527| ---@param part_id string Part ID\n00528| function M._remove_part_from_buffer(part_id)\n00529| local cached = M._render_state:get_part(part_id)\n00530| if not cached or not cached.line_start or not cached.line_end then\n00531| return\n00532| end\n00533| \n00534| if not state.windows or not state.windows.output_buf then\n00535| return\n00536| end\n00537| \n00538| output_window.clear_extmarks(cached.line_start - 1, cached.line_end)\n00539| output_window.set_lines({}, cached.line_start - 1, cached.line_end)\n00540| \n00541| M._render_state:remove_part(part_id)\n00542| end\n00543| \n00544| ---Remove message header from buffer and adjust subsequent line positions\n00545| ---@param message_id string Message ID\n00546| function M._remove_message_from_buffer(message_id)\n00547| local cached = M._render_state:get_message(message_id)\n00548| if not cached or not cached.line_start or not cached.line_end then\n00549| return\n00550| end\n00551| \n00552| if not state.windows or not state.windows.output_buf then\n00553| return\n00554| end\n00555| \n00556| output_window.clear_extmarks(cached.line_start - 1, cached.line_end)\n00557| output_window.set_lines({}, cached.line_start - 1, cached.line_end)\n00558| \n00559| M._render_state:remove_message(message_id)\n00560| end\n00561| \n00562| ---Adds a message (most likely just a header) to the buffer\n00563| ---@param message OpencodeMessage Message to add\n00564| function M._add_message_to_buffer(message)\n00565| local header_data = formatter.format_message_header(message)\n00566| local range = M._write_formatted_data(header_data)\n00567| \n00568| if range then\n00569| M._render_state:set_message(message, range.line_start, range.line_end)\n00570| end\n00571| end\n00572| \n00573| ---Replace existing message header in buffer\n00574| ---@param message_id string Message ID\n00575| ---@param formatted_data Output Formatted header as Output object\n00576| ---@return boolean Success status\n00577| function M._replace_message_in_buffer(message_id, formatted_data)\n00578| local cached = M._render_state:get_message(message_id)\n00579| if not cached or not cached.line_start or not cached.line_end then\n00580| return false\n00581| end\n00582| \n00583| local new_lines = formatted_data.lines\n00584| local new_line_count = #new_lines\n00585| \n00586| output_window.clear_extmarks(cached.line_start, cached.line_end + 1)\n00587| output_window.set_lines(new_lines, cached.line_start, cached.line_end + 1)\n00588| output_window.set_extmarks(formatted_data.extmarks, cached.line_start)\n00589| \n00590| local old_line_end = cached.line_end\n00591| local new_line_end = cached.line_start + new_line_count - 1\n00592| \n00593| M._render_state:set_message(cached.message, cached.line_start, new_line_end)\n00594| \n00595| local delta = new_line_end - old_line_end\n00596| if delta ~= 0 then\n00597| M._render_state:shift_all(old_line_end + 1, delta)\n00598| end\n00599| \n00600| return true\n00601| end\n00602| \n00603| ---Event handler for message.updated events\n00604| ---Creates new message or updates existing message info\n00605| ---@param message {info: MessageInfo} Event properties\n00606| ---@param revert_index? integer Revert index in session, if applicable\n00607| function M.on_message_updated(message, revert_index)\n00608| if not state.active_session or not state.messages then\n00609| return\n00610| end\n00611| \n00612| local msg = message --[[@as OpencodeMessage]]\n00613| if not msg or not msg.info or not msg.info.id or not msg.info.sessionID then\n00614| return\n00615| end\n00616| \n00617| if state.active_session.id ~= msg.info.sessionID then\n00618| ---@TODO This is probably a child session message, handle differently?\n00619| -- vim.notify('Session id does not match, discarding message: ' .. vim.inspect(message), vim.log.levels.WARN)\n00620| return\n00621| end\n00622| \n00623| local rendered_message = M._render_state:get_message(msg.info.id)\n00624| local found_msg = rendered_message and rendered_message.message\n00625| \n00626| if revert_index then\n00627| if not found_msg then\n00628| table.insert(state.messages, msg)\n00629| end\n00630| M._render_state:set_message(msg, 0, 0)\n00631| return\n00632| end\n00633| \n00634| if found_msg then\n00635| local error_changed = not vim.deep_equal(found_msg.info.error, msg.info.error)\n00636| \n00637| found_msg.info = msg.info\n00638| \n00639| --- NOTE: error handling is a bit messy because errors come in on messages\n00640| --- but we want to display the error at the end. In this case, we an error\n00641| --- was added to this message. We find the last part and re-render it to\n00642| --- display the message. If there are no parts, we'll re-render the message\n00643| \n00644| if error_changed and not revert_index then\n00645| local last_part_id = M._get_last_part_for_message(found_msg)\n00646| if last_part_id then\n00647| M._rerender_part(last_part_id)\n00648| else\n00649| local header_data = formatter.format_message_header(found_msg)\n00650| M._replace_message_in_buffer(msg.info.id, header_data)\n00651| end\n00652| end\n00653| else\n00654| table.insert(state.messages, msg)\n00655| \n00656| M._add_message_to_buffer(msg)\n00657| \n00658| state.current_message = msg\n00659| if message.info.role == 'user' then\n00660| state.last_user_message = msg\n00661| end\n00662| end\n00663| \n00664| M._update_stats_from_message(msg)\n00665| end\n00666| \n00667| ---Event handler for message.part.updated events\n00668| ---Inserts new parts or replaces existing parts in buffer\n00669| ---@param properties {part: OpencodeMessagePart} Event properties\n00670| ---@param revert_index? integer Revert index in session, if applicable\n00671| function M.on_part_updated(properties, revert_index)\n00672| if not properties or not properties.part or not state.active_session then\n00673| return\n00674| end\n00675| \n00676| local part = properties.part\n00677| if not part.id or not part.messageID or not part.sessionID then\n00678| return\n00679| end\n00680| \n00681| if state.active_session.id ~= part.sessionID then\n00682| ---@TODO This is probably a child session part, handle differently?\n00683| -- vim.notify('Session id does not match, discarding part: ' .. vim.inspect(part), vim.log.levels.WARN)\n00684| return\n00685| end\n00686| \n00687| local rendered_message = M._render_state:get_message(part.messageID)\n00688| if not rendered_message or not rendered_message.message then\n00689| vim.notify('Could not find message for part: ' .. vim.inspect(part), vim.log.levels.WARN)\n00690| return\n00691| end\n00692| \n00693| local message = rendered_message.message\n00694| \n00695| message.parts = message.parts or {}\n00696| \n00697| local part_data = M._render_state:get_part(part.id)\n00698| local is_new_part = not part_data\n00699| \n00700| local prev_last_part_id = M._get_last_part_for_message(message)\n00701| local is_last_part = is_new_part or (prev_last_part_id == part.id)\n00702| \n00703| if is_new_part then\n00704| table.insert(message.parts, part)\n00705| else\n00706| for i = #message.parts, 1, -1 do\n00707| if message.parts[i].id == part.id then\n00708| message.parts[i] = part\n00709| break\n00710| end\n00711| end\n00712| end\n00713| \n00714| if part.type == 'step-start' or part.type == 'step-finish' then\n00715| return\n00716| end\n00717| \n00718| if is_new_part then\n00719| M._render_state:set_part(part)\n00720| else\n00721| local rendered_part = M._render_state:update_part_data(part)\n00722| -- NOTE: This isn't the first time we've seen the part but we haven't rendered it previously\n00723| -- so try and render it this time by setting is_new_part = true (otherwise we'd call\n00724| -- _replace_message_in_buffer and it wouldn't do anything because the part hasn't been rendered)\n00725| if not rendered_part or (not rendered_part.line_start and not rendered_part.line_end) then\n00726| is_new_part = true\n00727| end\n00728| end\n00729| \n00730| local formatted = formatter.format_part(part, message, is_last_part)\n00731| \n00732| if revert_index and is_new_part then\n00733| return\n00734| end\n00735| \n00736| if is_new_part then\n00737| M._insert_part_to_buffer(part.id, formatted)\n00738| \n00739| if message.info.error then\n00740| --- NOTE: More error display code. As mentioned above, errors come in on messages\n00741| --- but we want to display them after parts so we tack the error onto the last\n00742| --- part. When a part is added and there's an error, we need to rerender\n00743| --- previous last part so it doesn't also display the message. If there was no previous\n00744| --- part, then we need to rerender the header so it doesn't display the error\n00745| \n00746| if not prev_last_part_id then\n00747| -- no previous part, we're the first part, re-render the message header\n00748| -- so it doesn't also display the error\n00749| local header_data = formatter.format_message_header(message)\n00750| M._replace_message_in_buffer(part.messageID, header_data)\n00751| elseif prev_last_part_id ~= part.id then\n00752| M._rerender_part(prev_last_part_id)\n00753| end\n00754| end\n00755| else\n00756| M._replace_part_in_buffer(part.id, formatted)\n00757| end\n00758| \n00759| if (part.type == 'file' or part.type == 'agent') and part.source then\n00760| -- we have a mention, we need to rerender the early part to highlight\n00761| -- the mention.\n00762| local text_part_id = M._find_text_part_for_message(message)\n00763| if text_part_id then\n00764| M._rerender_part(text_part_id)\n00765| end\n00766| end\n00767| end\n00768| \n00769| ---Event handler for message.part.removed events\n00770| ---@param properties {sessionID: string, messageID: string, partID: string} Event properties\n00771| function M.on_part_removed(properties)\n00772| if not properties then\n00773| return\n00774| end\n00775| \n00776| local part_id = properties.partID\n00777| if not part_id then\n00778| return\n00779| end\n00780| \n00781| local cached = M._render_state:get_part(part_id)\n00782| if cached and cached.message_id then\n00783| local rendered_message = M._render_state:get_message(cached.message_id)\n00784| if rendered_message and rendered_message.message then\n00785| local message = rendered_message.message\n00786| if message.parts then\n00787| for i, part in ipairs(message.parts) do\n00788| if part.id == part_id then\n00789| table.remove(message.parts, i)\n00790| break\n00791| end\n00792| end\n00793| end\n00794| end\n00795| end\n00796| \n00797| M._remove_part_from_buffer(part_id)\n00798| end\n00799| \n00800| ---Event handler for message.removed events\n00801| ---Removes message and all its parts from buffer\n00802| ---@param properties {sessionID: string, messageID: string} Event properties\n00803| function M.on_message_removed(properties)\n00804| if not properties or not state.messages then\n00805| return\n00806| end\n00807| \n00808| local message_id = properties.messageID\n00809| if not message_id then\n00810| return\n00811| end\n00812| \n00813| local rendered_message = M._render_state:get_message(message_id)\n00814| if not rendered_message or not rendered_message.message then\n00815| return\n00816| end\n00817| \n00818| local message = rendered_message.message\n00819| for _, part in ipairs(message.parts or {}) do\n00820| if part.id then\n00821| M._remove_part_from_buffer(part.id)\n00822| end\n00823| end\n00824| \n00825| M._remove_message_from_buffer(message_id)\n00826| \n00827| for i, msg in ipairs(state.messages or {}) do\n00828| if msg.info.id == message_id then\n00829| table.remove(state.messages, i)\n00830| break\n00831| end\n00832| end\n00833| end\n00834| \n00835| ---Event handler for session.compacted events\n00836| ---@param properties {sessionID: string} Event properties\n00837| function M.on_session_compacted(properties)\n00838| vim.notify('Session has been compacted')\n00839| end\n00840| \n00841| ---Event handler for session.updated events\n00842| ---@param properties {info: Session}\n00843| function M.on_session_updated(properties)\n00844| if not properties or not properties.info or not state.active_session then\n00845| return\n00846| end\n00847| if not vim.deep_equal(state.active_session.revert, properties.info.revert) then\n00848| state.active_session.revert = properties.info.revert\n00849| M._render_full_session_data(state.messages)\n00850| end\n00851| end\n00852| \n00853| ---Event handler for session.error events\n00854| ---@param properties {sessionID: string, error: table} Event properties\n00855| function M.on_session_error(properties)\n00856| if not properties or not properties.error then\n00857| return\n00858| end\n00859| \n00860| -- NOTE: we're handling message errors so session errors seem duplicative\n00861| if config.debug.enabled then\n00862| vim.notify('Session error: ' .. vim.inspect(properties.error))\n00863| end\n00864| end\n00865| \n00866| ---Event handler for permission.updated events\n00867| ---Re-renders part that requires permission and adds to permission window\n00868| ---@param permission OpencodePermission Event properties\n00869| function M.on_permission_updated(permission)\n00870| local tool = permission.tool\n00871| \n00872| ---@TODO this is for backward compatibility, remove later\n00873| local callID = tool and tool.callID or permission.callID\n00874| local messageID = tool and tool.messageID or permission.messageID\n00875| \n00876| if not permission or not messageID or not callID then\n00877| return\n00878| end\n00879| \n00880| -- Add permission to pending queue\n00881| if not state.pending_permissions then\n00882| state.pending_permissions = {}\n00883| end\n00884| \n00885| -- Check if permission already exists in queue\n00886| local existing_index = nil\n00887| for i, existing in ipairs(state.pending_permissions) do\n00888| if existing.id == permission.id then\n00889| existing_index = i\n00890| break\n00891| end\n00892| end\n00893| \n00894| local permissions = vim.deepcopy(state.pending_permissions)\n00895| if existing_index then\n00896| permissions[existing_index] = permission\n00897| else\n00898| table.insert(permissions, permission)\n00899| end\n00900| state.pending_permissions = permissions\n00901| \n00902| permission_window.add_permission(permission)\n00903| \n00904| M.render_permissions_display()\n00905| \n00906| M._rerender_part('permission-display-part')\n00907| M.scroll_to_bottom()\n00908| end\n00909| \n00910| ---Event handler for permission.replied events\n00911| ---Re-renders part after permission is resolved and removes from window\n00912| ---@param properties {sessionID: string, permissionID?: string,requestID?: string, response: string}|{} Event properties\n00913| function M.on_permission_replied(properties)\n00914| if not properties then\n00915| return\n00916| end\n00917| \n00918| local permission_id = properties.permissionID or properties.requestID\n00919| \n00920| if permission_id then\n00921| permission_window.remove_permission(permission_id)\n00922| state.pending_permissions = vim.deepcopy(permission_window.get_all_permissions())\n00923| if #state.pending_permissions == 0 then\n00924| M._remove_part_from_buffer('permission-display-part')\n00925| M._remove_message_from_buffer('permission-display-message')\n00926| end\n00927| M._rerender_part('permission-display-part')\n00928| end\n00929| end\n00930| \n00931| ---Event handler for question.asked events\n00932| ---Shows the question picker UI for the user to answer\n00933| ---@param properties OpencodeQuestionRequest Event properties\n00934| function M.on_question_asked(properties)\n00935| if not properties or not properties.id or not properties.questions then\n00936| return\n00937| end\n00938| \n00939| if not state.active_session or properties.sessionID ~= state.active_session.id then\n00940| return\n00941| end\n00942| \n00943| local question_window = require('opencode.ui.question_window')\n00944| question_window.show_question(properties)\n00945| end\n00946| \n00947| function M.on_file_edited(properties)\n00948| vim.cmd('checktime')\n00949| if config.hooks and config.hooks.on_file_edited then\n00950| pcall(config.hooks.on_file_edited, properties.file)\n00951| end\n00952| end\n00953| \n00954| ---@param properties RestorePointCreatedEvent\n00955| function M.on_restore_points(properties)\n00956| state.append('restore_points', properties.restore_point)\n00957| if not properties or not properties.restore_point or not properties.restore_point.from_snapshot_id then\n00958| return\n00959| end\n00960| local part = M._render_state:get_part_by_snapshot_id(properties.restore_point.from_snapshot_id)\n00961| if part then\n00962| M.on_part_updated({ part = part })\n00963| end\n00964| end\n00965| \n00966| ---Find part ID by call ID and message ID\n00967| ---Useful for finding a part for a permission\n00968| ---@param call_id string Call ID to search for\n00969| ---@param message_id string Message ID to check the parts of\n00970| ---@return string? part_id Part ID if found, nil otherwise\n00971| function M._find_part_by_call_id(call_id, message_id)\n00972| return M._render_state:get_part_by_call_id(call_id, message_id)\n00973| end\n00974| \n00975| ---Find the text part in a message\n00976| ---@param message OpencodeMessage The message containing the parts\n00977| ---@return string? text_part_id The ID of the text part\n00978| function M._find_text_part_for_message(message)\n00979| if not message or not message.parts then\n00980| return nil\n00981| end\n00982| \n00983| for _, part in ipairs(message.parts) do\n00984| if part.type == 'text' and not part.synthetic then\n00985| return part.id\n00986| end\n00987| end\n00988| \n00989| return nil\n00990| end\n00991| \n00992| ---Find the last part in a message\n00993| ---@param message OpencodeMessage The message containing the parts\n00994| ---@return string? last_part_id The ID of the last part\n00995| function M._get_last_part_for_message(message)\n00996| if not message or not message.parts or #message.parts == 0 then\n00997| return nil\n00998| end\n00999| \n01000| for i = #message.parts, 1, -1 do\n01001| local part = message.parts[i]\n01002| if part.type ~= 'step-start' and part.type ~= 'step-finish' and part.id then\n01003| return part.id\n01004| end\n01005| end\n01006| \n01007| return nil\n01008| end\n01009| \n01010| ---Get insertion point for an out-of-order part\n01011| ---@param part_id string The part ID to insert\n01012| ---@param message_id string The message ID the part belongs to\n01013| ---@return integer? insertion_line The line to insert at (1-indexed), or nil on error\n01014| function M._get_insertion_point_for_part(part_id, message_id)\n01015| local rendered_message = M._render_state:get_message(message_id)\n01016| if not rendered_message or not rendered_message.message then\n01017| return nil\n01018| end\n01019| \n01020| local message = rendered_message.message\n01021| \n01022| local insertion_line = rendered_message.line_end and (rendered_message.line_end + 1)\n01023| if not insertion_line then\n01024| return nil\n01025| end\n01026| \n01027| local current_part_index = nil\n01028| if message.parts then\n01029| for i, part in ipairs(message.parts) do\n01030| if part.id == part_id then\n01031| current_part_index = i\n01032| break\n01033| end\n01034| end\n01035| end\n01036| \n01037| if not current_part_index then\n01038| return insertion_line\n01039| end\n01040| \n01041| for i = current_part_index - 1, 1, -1 do\n01042| local prev_part = message.parts[i]\n01043| if prev_part and prev_part.id then\n01044| local prev_rendered = M._render_state:get_part(prev_part.id)\n01045| \n01046| if prev_rendered and prev_rendered.line_end then\n01047| return prev_rendered.line_end + 1\n01048| end\n01049| end\n01050| end\n01051| \n01052| return insertion_line\n01053| end\n01054| \n01055| ---Re-render existing part with current state\n01056| ---Used for permission updates and other dynamic changes\n01057| ---@param part_id string Part ID to re-render\n01058| function M._rerender_part(part_id)\n01059| local cached = M._render_state:get_part(part_id)\n01060| if not cached or not cached.part then\n01061| return\n01062| end\n01063| \n01064| local part = cached.part\n01065| local rendered_message = M._render_state:get_message(cached.message_id)\n01066| if not rendered_message or not rendered_message.message then\n01067| return\n01068| end\n01069| \n01070| local message = rendered_message.message\n01071| local last_part_id = M._get_last_part_for_message(message)\n01072| local is_last_part = (last_part_id == part_id)\n01073| local formatted = formatter.format_part(part, message, is_last_part)\n01074| \n01075| M._replace_part_in_buffer(part_id, formatted)\n01076| end\n01077| \n01078| ---Event handler for focus changes\n01079| ---Re-renders part associated with current permission for displaying global shortcuts or buffer-local ones\n01080| function M.on_focus_changed()\n01081| -- Check permission window first, fallback to state\n01082| local current_permission = permission_window.get_all_permissions()[1]\n01083| \n01084| if not current_permission then\n01085| return\n01086| end\n01087| \n01088| M._rerender_part('permission-display-part')\n01089| trigger_on_data_rendered()\n01090| end\n01091| \n01092| function M.on_session_changed(_, new, _)\n01093| M.reset()\n01094| if new then\n01095| M.render_full_session()\n01096| end\n01097| end\n01098| \n01099| ---Get all actions available at a specific line\n01100| ---@param line integer 0-indexed line number\n01101| ---@return table[] List of actions available at that line\n01102| function M.get_actions_for_line(line)\n01103| return M._render_state:get_actions_at_line(line)\n01104| end\n01105| \n01106| ---Update display stats from a single message\n01107| ---@param message OpencodeMessage\n01108| function M._update_stats_from_message(message)\n01109| if not state.current_model and message.info.providerID and message.info.providerID ~= '' then\n01110| state.current_model = message.info.providerID .. '/' .. message.info.modelID\n01111| end\n01112| \n01113| local tokens = message.info.tokens\n01114| if tokens and tokens.input > 0 then\n01115| state.tokens_count = tokens.input + tokens.output + tokens.cache.read + tokens.cache.write\n01116| end\n01117| \n01118| if message.info.cost and type(message.info.cost) == 'number' then\n01119| state.cost = message.info.cost\n01120| end\n01121| end\n01122| \n01123| ---Get rendered message by ID\n01124| ---@param message_id string Message ID\n01125| ---@return RenderedMessage|nil Rendered message or nil if not found\n01126| function M.get_rendered_message(message_id)\n01127| local rendered_msg = M._render_state:get_message(message_id)\n01128| if rendered_msg then\n01129| return rendered_msg\n01130| end\n01131| return nil\n01132| end\n01133| \n01134| return M\n01135| \n\n(End of file - total 1135 lines)\n",
+ "type": "text",
+ "id": "prt_bfaa078ae001zhO39Uz3en7btW"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "filename": "lua/opencode/ui/renderer.lua",
+ "messageID": "msg_bfaa078a2001RUYhlKZhSlyWeF",
+ "type": "file",
+ "id": "prt_bfaa078ae002XvKak6z08HB5LV",
+ "url": "file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/renderer.lua",
+ "mime": "text/plain",
+ "sessionID": "ses_4055f967bffeIHf3DnP0xntmxD"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "messageID": "msg_bfaa078a2001RUYhlKZhSlyWeF",
+ "text": "can you use the question tool and ask me a question with an other choice",
+ "id": "prt_bfaa078a4001OxXpwZJxaFmqUo",
+ "type": "text",
+ "sessionID": "ses_4055f967bffeIHf3DnP0xntmxD"
+ }
+ }
+ },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "version": "1.1.31",
+ "slug": "calm-lagoon",
+ "id": "ses_4055f967bffeIHf3DnP0xntmxD",
+ "title": "New session - 2026-01-26T14:06:15.428Z",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "time": { "created": 1769436375428, "updated": 1769436379349 }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "path": {
+ "root": "/home/francis/Projects/_nvim/opencode.nvim",
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "modelID": "gpt-4.1",
+ "providerID": "github-copilot",
+ "id": "msg_bfaa078e7001qc33BqBlqzHv8X",
+ "agent": "build",
+ "mode": "build",
+ "tokens": { "reasoning": 0, "input": 0, "cache": { "read": 0, "write": 0 }, "output": 0 },
+ "parentID": "msg_bfaa078a2001RUYhlKZhSlyWeF",
+ "sessionID": "ses_4055f967bffeIHf3DnP0xntmxD",
+ "role": "assistant",
+ "cost": 0,
+ "time": { "created": 1769436379367 }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "time": { "created": 1769436379298 },
+ "id": "msg_bfaa078a2001RUYhlKZhSlyWeF",
+ "agent": "build",
+ "sessionID": "ses_4055f967bffeIHf3DnP0xntmxD",
+ "role": "user",
+ "model": { "modelID": "gpt-4.1", "providerID": "github-copilot" },
+ "summary": { "diffs": [] }
+ }
+ }
+ },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "version": "1.1.31",
+ "title": "New session - 2026-01-26T14:06:15.428Z",
+ "slug": "calm-lagoon",
+ "id": "ses_4055f967bffeIHf3DnP0xntmxD",
+ "time": { "created": 1769436375428, "updated": 1769436379539 },
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "summary": { "deletions": 0, "files": 0, "additions": 0 }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "messageID": "msg_bfaa078e7001qc33BqBlqzHv8X",
+ "id": "prt_bfaa07ecf0011yakDSUtAyStvx",
+ "sessionID": "ses_4055f967bffeIHf3DnP0xntmxD",
+ "type": "step-start",
+ "snapshot": "56238d5c6bb499e9e265444377a201fba6b1a880"
+ }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "id": "prt_bfaa07ed3001RYplcvPxb660OT",
+ "type": "tool",
+ "tool": "question",
+ "state": { "raw": "", "status": "pending", "input": {} },
+ "sessionID": "ses_4055f967bffeIHf3DnP0xntmxD",
+ "messageID": "msg_bfaa078e7001qc33BqBlqzHv8X",
+ "callID": "call_IpPBuTk1riUXZDmDUDghZEpB"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "question.asked",
+ "properties": {
+ "id": "que_bfaa0833a001jKE5x0BCsGLOYX",
+ "sessionID": "ses_4055f967bffeIHf3DnP0xntmxD",
+ "questions": [
+ {
+ "header": "Favorite color",
+ "question": "What is your favorite color?",
+ "options": [
+ { "label": "Red", "description": "The color red" },
+ { "label": "Blue", "description": "The color blue" },
+ { "label": "Other", "description": "Any color not listed" }
+ ]
+ }
+ ],
+ "tool": { "messageID": "msg_bfaa078e7001qc33BqBlqzHv8X", "callID": "call_IpPBuTk1riUXZDmDUDghZEpB" }
+ }
+ },
+ {
+ "type": "message.part.updated",
+ "properties": {
+ "part": {
+ "id": "prt_bfaa07ed3001RYplcvPxb660OT",
+ "type": "tool",
+ "tool": "question",
+ "state": {
+ "status": "running",
+ "input": {
+ "questions": [
+ {
+ "header": "Favorite color",
+ "question": "What is your favorite color?",
+ "options": [
+ { "label": "Red", "description": "The color red" },
+ { "label": "Blue", "description": "The color blue" },
+ { "label": "Other", "description": "Any color not listed" }
+ ]
+ }
+ ]
+ },
+ "time": { "start": 1769436382010 }
+ },
+ "sessionID": "ses_4055f967bffeIHf3DnP0xntmxD",
+ "messageID": "msg_bfaa078e7001qc33BqBlqzHv8X",
+ "callID": "call_IpPBuTk1riUXZDmDUDghZEpB"
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "message.updated",
+ "properties": {
+ "info": {
+ "time": { "created": 1769436379298 },
+ "id": "msg_bfaa078a2001RUYhlKZhSlyWeF",
+ "agent": "build",
+ "sessionID": "ses_4055f967bffeIHf3DnP0xntmxD",
+ "role": "user",
+ "model": { "modelID": "gpt-4.1", "providerID": "github-copilot" },
+ "summary": { "diffs": [], "title": "Question including Other option" }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] },
+ {
+ "type": "session.updated",
+ "properties": {
+ "info": {
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "version": "1.1.31",
+ "title": "Question about opencode/ui/renderer.lua",
+ "slug": "calm-lagoon",
+ "id": "ses_4055f967bffeIHf3DnP0xntmxD",
+ "time": { "created": 1769436375428, "updated": 1769436379539 },
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "summary": { "deletions": 0, "files": 0, "additions": 0 }
+ }
+ }
+ },
+ { "type": "custom.emit_events.finished", "properties": [] }
+]
diff --git a/tests/data/reasoning.expected.json b/tests/data/reasoning.expected.json
index 65db68da..75c4f6ce 100644
--- a/tests/data/reasoning.expected.json
+++ b/tests/data/reasoning.expected.json
@@ -1 +1,389 @@
-{"actions":[],"timestamp":1766432126,"extmarks":[[1,1,0,{"virt_text_hide":false,"virt_text_pos":"win_col","virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-12-17 19:33:20)","OpencodeHint"],[" [msg_reason_user1]","OpencodeHint"]],"ns_id":3,"virt_text_win_col":-3,"priority":10,"virt_text_repeat_linebreak":false,"right_gravity":true}],[2,2,0,{"virt_text_hide":false,"virt_text_pos":"win_col","virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_win_col":-3,"priority":4096,"virt_text_repeat_linebreak":true,"right_gravity":true}],[3,3,0,{"virt_text_hide":false,"virt_text_pos":"win_col","virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_win_col":-3,"priority":4096,"virt_text_repeat_linebreak":true,"right_gravity":true}],[4,6,0,{"virt_text_hide":false,"virt_text_pos":"win_col","virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" claude-sonnet-4","OpencodeHint"],[" (2025-12-17 19:33:20)","OpencodeHint"],[" [msg_reason_asst1]","OpencodeHint"]],"ns_id":3,"virt_text_win_col":-3,"priority":10,"virt_text_repeat_linebreak":false,"right_gravity":true}],[5,8,0,{"virt_text_hide":false,"virt_text_repeat_linebreak":true,"ns_id":3,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"line_hl_group":"OpencodeReasoningText"}],[6,9,0,{"virt_text_hide":false,"virt_text_repeat_linebreak":true,"ns_id":3,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"line_hl_group":"OpencodeReasoningText"}],[7,10,0,{"virt_text_hide":false,"virt_text_repeat_linebreak":true,"ns_id":3,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"line_hl_group":"OpencodeReasoningText"}],[8,11,0,{"virt_text_hide":false,"virt_text_repeat_linebreak":true,"ns_id":3,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"line_hl_group":"OpencodeReasoningText"}],[9,12,0,{"virt_text_hide":false,"virt_text_repeat_linebreak":true,"ns_id":3,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"line_hl_group":"OpencodeReasoningText"}],[10,13,0,{"virt_text_hide":false,"virt_text_repeat_linebreak":true,"ns_id":3,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"line_hl_group":"OpencodeReasoningText"}],[11,14,0,{"virt_text_hide":false,"virt_text_repeat_linebreak":true,"ns_id":3,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"line_hl_group":"OpencodeReasoningText"}],[12,15,0,{"virt_text_hide":false,"virt_text_repeat_linebreak":true,"ns_id":3,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"line_hl_group":"OpencodeReasoningText"}],[13,16,0,{"virt_text_hide":false,"virt_text_repeat_linebreak":true,"ns_id":3,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"line_hl_group":"OpencodeReasoningText"}],[14,17,0,{"virt_text_hide":false,"virt_text_repeat_linebreak":true,"ns_id":3,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"line_hl_group":"OpencodeReasoningText"}],[15,18,0,{"virt_text_hide":false,"virt_text_repeat_linebreak":true,"ns_id":3,"right_gravity":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"line_hl_group":"OpencodeReasoningText"}]],"lines":["----","","","Explain your plan, then provide the final title.","","----","","","** Reasoning (2025-12-17 19:33:20 - 2025-12-17 19:33:21)** ","","The user is asking me to explain my plan and then provide a final title. I need to think through what they're asking for. It seems like they want me to demonstrate reasoning capabilities - showing my thought process before giving an answer. Let me break this down into steps.","","1. First, I should understand what kind of title they want - is this for a project, document, or something else?","2. Since they didn't specify the context, I should provide a general approach","3. I'll demonstrate my reasoning process transparently","4. Then I'll give them a concrete example title","","Given that this appears to be related to the OpenCode project (based on the file structure I can see), I should provide a title that reflects the nature of this AI coding assistant tool.","","Based on my reasoning above, here's my plan:","","1. Acknowledge the request for demonstrating reasoning","2. Show transparency in my thought process","3. Provide context-appropriate suggestions","","For the title, considering this is the OpenCode Neovim plugin - an AI-powered coding assistant - a good title would be:","","**\"OpenCode.nvim: AI-Powered Coding Assistant for Neovim\"**","","This title clearly identifies what the tool is (OpenCode), the platform it works with (Neovim), and its primary function (AI-powered coding assistance).","",""]}
\ No newline at end of file
+{
+ "actions": [],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-12-17 19:33:20)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_reason_user1]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 2,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 3,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 4,
+ 6,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " claude-sonnet-4",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-12-17 19:33:20)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_reason_asst1]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 5,
+ 8,
+ 0,
+ {
+ "line_hl_group": "OpencodeReasoningText",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 6,
+ 9,
+ 0,
+ {
+ "line_hl_group": "OpencodeReasoningText",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 7,
+ 10,
+ 0,
+ {
+ "line_hl_group": "OpencodeReasoningText",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 8,
+ 11,
+ 0,
+ {
+ "line_hl_group": "OpencodeReasoningText",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 9,
+ 12,
+ 0,
+ {
+ "line_hl_group": "OpencodeReasoningText",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 10,
+ 13,
+ 0,
+ {
+ "line_hl_group": "OpencodeReasoningText",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 11,
+ 14,
+ 0,
+ {
+ "line_hl_group": "OpencodeReasoningText",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 12,
+ 15,
+ 0,
+ {
+ "line_hl_group": "OpencodeReasoningText",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 13,
+ 16,
+ 0,
+ {
+ "line_hl_group": "OpencodeReasoningText",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 14,
+ 17,
+ 0,
+ {
+ "line_hl_group": "OpencodeReasoningText",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 15,
+ 18,
+ 0,
+ {
+ "line_hl_group": "OpencodeReasoningText",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "Explain your plan, then provide the final title.",
+ "",
+ "----",
+ "",
+ "",
+ "** Reasoning (2025-12-17 19:33:20 - 2025-12-17 19:33:21)** ",
+ "",
+ "The user is asking me to explain my plan and then provide a final title. I need to think through what they're asking for. It seems like they want me to demonstrate reasoning capabilities - showing my thought process before giving an answer. Let me break this down into steps.",
+ "",
+ "1. First, I should understand what kind of title they want - is this for a project, document, or something else?",
+ "2. Since they didn't specify the context, I should provide a general approach",
+ "3. I'll demonstrate my reasoning process transparently",
+ "4. Then I'll give them a concrete example title",
+ "",
+ "Given that this appears to be related to the OpenCode project (based on the file structure I can see), I should provide a title that reflects the nature of this AI coding assistant tool.",
+ "",
+ "Based on my reasoning above, here's my plan:",
+ "",
+ "1. Acknowledge the request for demonstrating reasoning",
+ "2. Show transparency in my thought process",
+ "3. Provide context-appropriate suggestions",
+ "",
+ "For the title, considering this is the OpenCode Neovim plugin - an AI-powered coding assistant - a good title would be:",
+ "",
+ "**\"OpenCode.nvim: AI-Powered Coding Assistant for Neovim\"**",
+ "",
+ "This title clearly identifies what the tool is (OpenCode), the platform it works with (Neovim), and its primary function (AI-powered coding assistance).",
+ "",
+ ""
+ ],
+ "timestamp": 1770748579
+}
\ No newline at end of file
diff --git a/tests/data/redo-all.expected.json b/tests/data/redo-all.expected.json
index db0265d9..58dd7d81 100644
--- a/tests/data/redo-all.expected.json
+++ b/tests/data/redo-all.expected.json
@@ -1 +1,1497 @@
-{"extmarks":[[1,1,0,{"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-20 15:20:02)","OpencodeHint"],[" [msg_a0234c0b7001y2o9S1jMaNVZar]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":10,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"right_gravity":true}],[2,2,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[3,3,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[4,4,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[5,5,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[6,8,0,{"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-5-mini","OpencodeHint"],[" (2025-10-20 15:20:04)","OpencodeHint"],[" [msg_a0234c7960011LTxTvD94hfWCi]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":10,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"right_gravity":true}],[7,12,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[8,13,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[9,14,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[10,15,0,{"ns_id":3,"end_col":0,"hl_group":"OpencodeDiffDelete","hl_eol":true,"virt_text":[["-","OpencodeDiffDelete"]],"end_right_gravity":false,"virt_text_hide":false,"priority":5000,"virt_text_pos":"overlay","end_row":16,"virt_text_repeat_linebreak":false,"right_gravity":true}],[11,15,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[12,16,0,{"ns_id":3,"end_col":0,"hl_group":"OpencodeDiffAdd","hl_eol":true,"virt_text":[["+","OpencodeDiffAdd"]],"end_right_gravity":false,"virt_text_hide":false,"priority":5000,"virt_text_pos":"overlay","end_row":17,"virt_text_repeat_linebreak":false,"right_gravity":true}],[13,16,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[14,17,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[15,18,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[16,19,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[17,20,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[18,25,0,{"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-5-mini","OpencodeHint"],[" (2025-10-20 15:20:09)","OpencodeHint"],[" [msg_a0234d8fb001SXyngLjuKSuxOY]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":10,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"right_gravity":true}],[19,30,0,{"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-20 15:20:11)","OpencodeHint"],[" [msg_a0234e308001SKl5bQUibp5gtI]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":10,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"right_gravity":true}],[20,31,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[21,32,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[22,35,0,{"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-5-mini","OpencodeHint"],[" (2025-10-20 15:20:11)","OpencodeHint"],[" [msg_a0234e31f001m4EsQdPmY3PTtS]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":10,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"right_gravity":true}],[23,42,0,{"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-5-mini","OpencodeHint"],[" (2025-10-20 15:20:16)","OpencodeHint"],[" [msg_a0234f482001PQbMjWc6W8s0eF]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":10,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"right_gravity":true}],[24,46,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[25,47,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[26,48,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[27,49,0,{"ns_id":3,"end_col":0,"hl_group":"OpencodeDiffDelete","hl_eol":true,"virt_text":[["-","OpencodeDiffDelete"]],"end_right_gravity":false,"virt_text_hide":false,"priority":5000,"virt_text_pos":"overlay","end_row":50,"virt_text_repeat_linebreak":false,"right_gravity":true}],[28,49,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[29,50,0,{"ns_id":3,"end_col":0,"hl_group":"OpencodeDiffAdd","hl_eol":true,"virt_text":[["+","OpencodeDiffAdd"]],"end_right_gravity":false,"virt_text_hide":false,"priority":5000,"virt_text_pos":"overlay","end_row":51,"virt_text_repeat_linebreak":false,"right_gravity":true}],[30,50,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[31,51,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[32,52,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[33,53,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[34,54,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[35,59,0,{"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-5-mini","OpencodeHint"],[" (2025-10-20 15:20:17)","OpencodeHint"],[" [msg_a0234f9c6001JCKYaca1HHwwx6]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":10,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"right_gravity":true}],[36,64,0,{"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-20 15:22:29)","OpencodeHint"],[" [msg_a0236fd1c001TlwqL8fwvq529i]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":10,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"right_gravity":true}],[37,65,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[38,66,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[39,69,0,{"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-5-mini","OpencodeHint"],[" (2025-10-20 15:22:29)","OpencodeHint"],[" [msg_a0236fd57001pTnTjSBdFlleCb]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":10,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"right_gravity":true}],[40,76,0,{"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-5-mini","OpencodeHint"],[" (2025-10-20 15:22:34)","OpencodeHint"],[" [msg_a02371241001PBQAsr8Oc9hqNI]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":10,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"right_gravity":true}],[41,80,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[42,81,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[43,82,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[44,83,0,{"ns_id":3,"end_col":0,"hl_group":"OpencodeDiffDelete","hl_eol":true,"virt_text":[["-","OpencodeDiffDelete"]],"end_right_gravity":false,"virt_text_hide":false,"priority":5000,"virt_text_pos":"overlay","end_row":84,"virt_text_repeat_linebreak":false,"right_gravity":true}],[45,83,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[46,84,0,{"ns_id":3,"end_col":0,"hl_group":"OpencodeDiffAdd","hl_eol":true,"virt_text":[["+","OpencodeDiffAdd"]],"end_right_gravity":false,"virt_text_hide":false,"priority":5000,"virt_text_pos":"overlay","end_row":85,"virt_text_repeat_linebreak":false,"right_gravity":true}],[47,84,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[48,85,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[49,86,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[50,87,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[51,88,0,{"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-1,"priority":4096,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"right_gravity":true}],[52,93,0,{"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-5-mini","OpencodeHint"],[" (2025-10-20 15:22:39)","OpencodeHint"],[" [msg_a023723d0001r87MaJThFssUw1]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"virt_text_win_col":-3,"priority":10,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"right_gravity":true}]],"timestamp":1770644135,"actions":[{"type":"diff_revert_selected_file","args":["1b6ba655c6c0d899965adff278ac6320d5fc3b12"],"range":{"from":22,"to":22},"key":"R","text":"[R]evert file","display_line":22},{"type":"diff_revert_all","args":["1b6ba655c6c0d899965adff278ac6320d5fc3b12"],"range":{"from":22,"to":22},"key":"A","text":"Revert [A]ll","display_line":22},{"type":"diff_open","args":["1b6ba655c6c0d899965adff278ac6320d5fc3b12"],"range":{"from":22,"to":22},"key":"D","text":"[D]iff","display_line":22},{"type":"diff_revert_selected_file","args":["d988cc85565b99017d40ad8baea20225165be9d5"],"range":{"from":90,"to":90},"key":"R","text":"[R]evert file","display_line":90},{"type":"diff_revert_all","args":["d988cc85565b99017d40ad8baea20225165be9d5"],"range":{"from":90,"to":90},"key":"A","text":"Revert [A]ll","display_line":90},{"type":"diff_open","args":["d988cc85565b99017d40ad8baea20225165be9d5"],"range":{"from":90,"to":90},"key":"D","text":"[D]iff","display_line":90},{"type":"diff_revert_selected_file","args":["57d83f5596cb1f142fbc681d3d93b7184f7f73cd"],"range":{"from":56,"to":56},"key":"R","text":"[R]evert file","display_line":56},{"type":"diff_revert_all","args":["57d83f5596cb1f142fbc681d3d93b7184f7f73cd"],"range":{"from":56,"to":56},"key":"A","text":"Revert [A]ll","display_line":56},{"type":"diff_open","args":["57d83f5596cb1f142fbc681d3d93b7184f7f73cd"],"range":{"from":56,"to":56},"key":"D","text":"[D]iff","display_line":56}],"lines":["----","","","add another word","","[`test.txt`](test.txt)","","----","","","I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line now.","","** edit** `/home/francis/Projects/_nvim/opencode.nvim/test.txt`","","`````txt"," tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more"," tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again"," "," ","","`````","","** Created Snapshot** `1b6ba655`","","----","","","**Done:** added the word `again` to `test.txt`.","","----","","","add another word","","----","","","I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the file.","","** read** `/home/francis/Projects/_nvim/opencode.nvim/test.txt`","","----","","","Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that line.","","** edit** `/home/francis/Projects/_nvim/opencode.nvim/test.txt`","","`````txt"," tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again"," tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2"," "," ","","`````","","** Created Snapshot** `57d83f55`","","----","","","**Done:** appended the word `again2` to `test.txt`.","","----","","","add another word","","----","","","I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the file.","","** read** `/home/francis/Projects/_nvim/opencode.nvim/test.txt`","","----","","","I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change now.","","** edit** `/home/francis/Projects/_nvim/opencode.nvim/test.txt`","","`````txt"," tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2"," tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3"," "," ","","`````","","** Created Snapshot** `d988cc85`","","----","","","**Done:** appended the word `again3` to `test.txt`.","",""]}
\ No newline at end of file
+{
+ "actions": [
+ {
+ "args": [
+ "d988cc85565b99017d40ad8baea20225165be9d5"
+ ],
+ "display_line": 90,
+ "key": "R",
+ "range": {
+ "from": 90,
+ "to": 90
+ },
+ "text": "[R]evert file",
+ "type": "diff_revert_selected_file"
+ },
+ {
+ "args": [
+ "d988cc85565b99017d40ad8baea20225165be9d5"
+ ],
+ "display_line": 90,
+ "key": "A",
+ "range": {
+ "from": 90,
+ "to": 90
+ },
+ "text": "Revert [A]ll",
+ "type": "diff_revert_all"
+ },
+ {
+ "args": [
+ "d988cc85565b99017d40ad8baea20225165be9d5"
+ ],
+ "display_line": 90,
+ "key": "D",
+ "range": {
+ "from": 90,
+ "to": 90
+ },
+ "text": "[D]iff",
+ "type": "diff_open"
+ },
+ {
+ "args": [
+ "1b6ba655c6c0d899965adff278ac6320d5fc3b12"
+ ],
+ "display_line": 22,
+ "key": "R",
+ "range": {
+ "from": 22,
+ "to": 22
+ },
+ "text": "[R]evert file",
+ "type": "diff_revert_selected_file"
+ },
+ {
+ "args": [
+ "1b6ba655c6c0d899965adff278ac6320d5fc3b12"
+ ],
+ "display_line": 22,
+ "key": "A",
+ "range": {
+ "from": 22,
+ "to": 22
+ },
+ "text": "Revert [A]ll",
+ "type": "diff_revert_all"
+ },
+ {
+ "args": [
+ "1b6ba655c6c0d899965adff278ac6320d5fc3b12"
+ ],
+ "display_line": 22,
+ "key": "D",
+ "range": {
+ "from": 22,
+ "to": 22
+ },
+ "text": "[D]iff",
+ "type": "diff_open"
+ },
+ {
+ "args": [
+ "57d83f5596cb1f142fbc681d3d93b7184f7f73cd"
+ ],
+ "display_line": 56,
+ "key": "R",
+ "range": {
+ "from": 56,
+ "to": 56
+ },
+ "text": "[R]evert file",
+ "type": "diff_revert_selected_file"
+ },
+ {
+ "args": [
+ "57d83f5596cb1f142fbc681d3d93b7184f7f73cd"
+ ],
+ "display_line": 56,
+ "key": "A",
+ "range": {
+ "from": 56,
+ "to": 56
+ },
+ "text": "Revert [A]ll",
+ "type": "diff_revert_all"
+ },
+ {
+ "args": [
+ "57d83f5596cb1f142fbc681d3d93b7184f7f73cd"
+ ],
+ "display_line": 56,
+ "key": "D",
+ "range": {
+ "from": 56,
+ "to": 56
+ },
+ "text": "[D]iff",
+ "type": "diff_open"
+ }
+ ],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:20:02)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a0234c0b7001y2o9S1jMaNVZar]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 2,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 3,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 4,
+ 4,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 5,
+ 5,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 6,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-5-mini",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:20:04)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a0234c7960011LTxTvD94hfWCi]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 7,
+ 12,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 8,
+ 13,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 9,
+ 14,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 10,
+ 15,
+ 0,
+ {
+ "end_col": 0,
+ "end_right_gravity": false,
+ "end_row": 16,
+ "hl_eol": true,
+ "hl_group": "OpencodeDiffDelete",
+ "ns_id": 3,
+ "priority": 5000,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "-",
+ "OpencodeDiffDelete"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "overlay",
+ "virt_text_repeat_linebreak": false
+ }
+ ],
+ [
+ 11,
+ 15,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 12,
+ 16,
+ 0,
+ {
+ "end_col": 0,
+ "end_right_gravity": false,
+ "end_row": 17,
+ "hl_eol": true,
+ "hl_group": "OpencodeDiffAdd",
+ "ns_id": 3,
+ "priority": 5000,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "+",
+ "OpencodeDiffAdd"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "overlay",
+ "virt_text_repeat_linebreak": false
+ }
+ ],
+ [
+ 13,
+ 16,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 14,
+ 17,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 15,
+ 18,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 16,
+ 19,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 17,
+ 20,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 18,
+ 25,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-5-mini",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:20:09)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a0234d8fb001SXyngLjuKSuxOY]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 19,
+ 30,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:20:11)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a0234e308001SKl5bQUibp5gtI]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 20,
+ 31,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 21,
+ 32,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 22,
+ 35,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-5-mini",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:20:11)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a0234e31f001m4EsQdPmY3PTtS]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 23,
+ 42,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-5-mini",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:20:16)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a0234f482001PQbMjWc6W8s0eF]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 24,
+ 46,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 25,
+ 47,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 26,
+ 48,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 27,
+ 49,
+ 0,
+ {
+ "end_col": 0,
+ "end_right_gravity": false,
+ "end_row": 50,
+ "hl_eol": true,
+ "hl_group": "OpencodeDiffDelete",
+ "ns_id": 3,
+ "priority": 5000,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "-",
+ "OpencodeDiffDelete"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "overlay",
+ "virt_text_repeat_linebreak": false
+ }
+ ],
+ [
+ 28,
+ 49,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 29,
+ 50,
+ 0,
+ {
+ "end_col": 0,
+ "end_right_gravity": false,
+ "end_row": 51,
+ "hl_eol": true,
+ "hl_group": "OpencodeDiffAdd",
+ "ns_id": 3,
+ "priority": 5000,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "+",
+ "OpencodeDiffAdd"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "overlay",
+ "virt_text_repeat_linebreak": false
+ }
+ ],
+ [
+ 30,
+ 50,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 31,
+ 51,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 32,
+ 52,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 33,
+ 53,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 34,
+ 54,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 35,
+ 59,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-5-mini",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:20:17)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a0234f9c6001JCKYaca1HHwwx6]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 36,
+ 64,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:22:29)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a0236fd1c001TlwqL8fwvq529i]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 37,
+ 65,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 38,
+ 66,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 39,
+ 69,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-5-mini",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:22:29)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a0236fd57001pTnTjSBdFlleCb]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 40,
+ 76,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-5-mini",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:22:34)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a02371241001PBQAsr8Oc9hqNI]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 41,
+ 80,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 42,
+ 81,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 43,
+ 82,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 44,
+ 83,
+ 0,
+ {
+ "end_col": 0,
+ "end_right_gravity": false,
+ "end_row": 84,
+ "hl_eol": true,
+ "hl_group": "OpencodeDiffDelete",
+ "ns_id": 3,
+ "priority": 5000,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "-",
+ "OpencodeDiffDelete"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "overlay",
+ "virt_text_repeat_linebreak": false
+ }
+ ],
+ [
+ 45,
+ 83,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 46,
+ 84,
+ 0,
+ {
+ "end_col": 0,
+ "end_right_gravity": false,
+ "end_row": 85,
+ "hl_eol": true,
+ "hl_group": "OpencodeDiffAdd",
+ "ns_id": 3,
+ "priority": 5000,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "+",
+ "OpencodeDiffAdd"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "overlay",
+ "virt_text_repeat_linebreak": false
+ }
+ ],
+ [
+ 47,
+ 84,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 48,
+ 85,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 49,
+ 86,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 50,
+ 87,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 51,
+ 88,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 52,
+ 93,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-5-mini",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:22:39)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a023723d0001r87MaJThFssUw1]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "add another word",
+ "",
+ "[`test.txt`](test.txt)",
+ "",
+ "----",
+ "",
+ "",
+ "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line now.",
+ "",
+ "** edit** `/home/francis/Projects/_nvim/opencode.nvim/test.txt`",
+ "",
+ "`````txt",
+ " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more",
+ " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again",
+ " ",
+ " ",
+ "",
+ "`````",
+ "",
+ "** Created Snapshot** `1b6ba655`",
+ "",
+ "----",
+ "",
+ "",
+ "**Done:** added the word `again` to `test.txt`.",
+ "",
+ "----",
+ "",
+ "",
+ "add another word",
+ "",
+ "----",
+ "",
+ "",
+ "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the file.",
+ "",
+ "** read** `/home/francis/Projects/_nvim/opencode.nvim/test.txt`",
+ "",
+ "----",
+ "",
+ "",
+ "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that line.",
+ "",
+ "** edit** `/home/francis/Projects/_nvim/opencode.nvim/test.txt`",
+ "",
+ "`````txt",
+ " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again",
+ " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2",
+ " ",
+ " ",
+ "",
+ "`````",
+ "",
+ "** Created Snapshot** `57d83f55`",
+ "",
+ "----",
+ "",
+ "",
+ "**Done:** appended the word `again2` to `test.txt`.",
+ "",
+ "----",
+ "",
+ "",
+ "add another word",
+ "",
+ "----",
+ "",
+ "",
+ "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the file.",
+ "",
+ "** read** `/home/francis/Projects/_nvim/opencode.nvim/test.txt`",
+ "",
+ "----",
+ "",
+ "",
+ "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change now.",
+ "",
+ "** edit** `/home/francis/Projects/_nvim/opencode.nvim/test.txt`",
+ "",
+ "`````txt",
+ " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2",
+ " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3",
+ " ",
+ " ",
+ "",
+ "`````",
+ "",
+ "** Created Snapshot** `d988cc85`",
+ "",
+ "----",
+ "",
+ "",
+ "**Done:** appended the word `again3` to `test.txt`.",
+ "",
+ ""
+ ],
+ "timestamp": 1770748580
+}
\ No newline at end of file
diff --git a/tests/data/redo-all.json b/tests/data/redo-all.json
index 193b230b..0873780a 100644
--- a/tests/data/redo-all.json
+++ b/tests/data/redo-all.json
@@ -1 +1,4278 @@
-[{"properties":{},"type":"server.connected"},{"properties":{"info":{"id":"msg_a0234c0b7001y2o9S1jMaNVZar","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973602999},"role":"user"}},"type":"message.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","text":"add another word\n","id":"prt_a0234c0b8001E8tvDdVNT0NiFh","type":"text","messageID":"msg_a0234c0b7001y2o9S1jMaNVZar"}},"type":"message.part.updated"},{"properties":{"part":{"synthetic":true,"type":"text","text":"Called the Read tool with the following input: {\"filePath\":\"/home/francis/Projects/_nvim/opencode.nvim/test.txt\"}","id":"prt_a0234c0ba001p2wDCCzgtdcf9g","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c0b7001y2o9S1jMaNVZar"}},"type":"message.part.updated"},{"properties":{"part":{"synthetic":true,"type":"text","text":"\n00001| tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more\n00002| \n00003| \n00004| \n","id":"prt_a0234c0ba002ifWGZD21JdnYs6","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c0b7001y2o9S1jMaNVZar"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","type":"file","url":"file:///home/francis/Projects/_nvim/opencode.nvim/test.txt","mime":"text/plain","id":"prt_a0234c0ba003rwMIYGQq901md0","filename":"test.txt","messageID":"msg_a0234c0b7001y2o9S1jMaNVZar"}},"type":"message.part.updated"},{"properties":{"info":{"version":"0.14.6","time":{"created":1760973600383,"updated":1760973603008},"directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"New session - 2025-10-20T15:20:00.383Z"}},"type":"session.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973604758},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234c7960011LTxTvD94hfWCi","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"version":"0.14.6","time":{"created":1760973600383,"updated":1760973605391},"directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Adding word to test.txt"}},"type":"session.updated"},{"properties":{"part":{"type":"step-start","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","id":"prt_a0234d6050012gZEes0qoo3vws","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\")","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`.","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line now","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line now.","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_f5xkch2vMvn01ko5Ko4GzNbL","type":"tool","state":{"status":"pending"},"id":"prt_a0234d89c001EJCQkv3qyPNYjc","tool":"edit","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_f5xkch2vMvn01ko5Ko4GzNbL","type":"tool","state":{"input":{"oldString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more","filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt","newString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again"},"time":{"start":1760973609159},"status":"running"},"id":"prt_a0234d89c001EJCQkv3qyPNYjc","tool":"edit","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"file":"/home/francis/Projects/_nvim/opencode.nvim/test.txt"},"type":"file.edited"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_f5xkch2vMvn01ko5Ko4GzNbL","type":"tool","state":{"title":"test.txt","time":{"end":1760973609163,"start":1760973609159},"input":{"oldString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more","filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt","newString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again"},"status":"completed","output":"","metadata":{"diagnostics":{},"diff":"Index: /home/francis/Projects/_nvim/opencode.nvim/test.txt\n===================================================================\n--- /home/francis/Projects/_nvim/opencode.nvim/test.txt\n+++ /home/francis/Projects/_nvim/opencode.nvim/test.txt\n@@ -1,3 +1,3 @@\n-tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again\n \n \n"}},"id":"prt_a0234d89c001EJCQkv3qyPNYjc","tool":"edit","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"end":1760973609181,"start":1760973609181},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line now.","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"cost":0,"type":"step-finish","tokens":{"reasoning":0,"input":12788,"output":514,"cache":{"write":0,"read":7168}},"id":"prt_a0234d8df001tlclk7glXfU1WC","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973604758},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12788,"output":514,"cache":{"write":0,"read":7168}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234c7960011LTxTvD94hfWCi","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"hash":"1b6ba655c6c0d899965adff278ac6320d5fc3b12","type":"patch","files":["/home/francis/Projects/_nvim/opencode.nvim/test.txt"],"id":"prt_a0234d8f0001GsHhf2mPuESk1p","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973604758,"completed":1760973609201},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12788,"output":514,"cache":{"write":0,"read":7168}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234c7960011LTxTvD94hfWCi","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973604758,"completed":1760973609207},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12788,"output":514,"cache":{"write":0,"read":7168}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234c7960011LTxTvD94hfWCi","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973604758,"completed":1760973609207},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12788,"output":514,"cache":{"write":0,"read":7168}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234c7960011LTxTvD94hfWCi","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973609211},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234d8fb001SXyngLjuKSuxOY","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"type":"step-start","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","id":"prt_a0234dbf00016c9aOHUxpQxM0U","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:**","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word `","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word `again","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word `again`","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word `again` to","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word `again` to `","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word `again` to `test","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word `again` to `test.txt","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word `again` to `test.txt`.","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"end":1760973609987,"start":1760973609987},"text":"**Done:** added the word `again` to `test.txt`.","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"cost":0,"type":"step-finish","tokens":{"reasoning":0,"input":12921,"output":18,"cache":{"write":0,"read":12672}},"id":"prt_a0234dc03001iO2ubPxctfhnkY","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973609211},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12921,"output":18,"cache":{"write":0,"read":12672}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234d8fb001SXyngLjuKSuxOY","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973609211,"completed":1760973610000},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12921,"output":18,"cache":{"write":0,"read":12672}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234d8fb001SXyngLjuKSuxOY","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973609211,"completed":1760973610001},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12921,"output":18,"cache":{"write":0,"read":12672}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234d8fb001SXyngLjuKSuxOY","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973609211,"completed":1760973610002},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12921,"output":18,"cache":{"write":0,"read":12672}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234d8fb001SXyngLjuKSuxOY","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0"},"type":"session.idle"},{"properties":{"info":{"id":"msg_a0234e308001SKl5bQUibp5gtI","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973611784},"role":"user"}},"type":"message.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","text":"add another word\n","id":"prt_a0234e308002nvLNQpQkMykslq","type":"text","messageID":"msg_a0234e308001SKl5bQUibp5gtI"}},"type":"message.part.updated"},{"properties":{"info":{"version":"0.14.6","time":{"created":1760973600383,"updated":1760973611785},"directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Adding word to test.txt"}},"type":"session.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973611807},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234e31f001m4EsQdPmY3PTtS","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"type":"step-start","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","id":"prt_a0234f2d9001o5Ev43oSWT3Wum","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt`","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content,","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\")","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line.","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceed","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the file","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the file.","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_YtG0tPTwncFNNWTaUP6XeTAe","type":"tool","state":{"status":"pending"},"id":"prt_a0234f463001u4vZX0ePvjr6ew","tool":"read","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_YtG0tPTwncFNNWTaUP6XeTAe","type":"tool","state":{"input":{"filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt"},"time":{"start":1760973616230},"status":"running"},"id":"prt_a0234f463001u4vZX0ePvjr6ew","tool":"read","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"end":1760973616230,"start":1760973616230},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the file.","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_YtG0tPTwncFNNWTaUP6XeTAe","type":"tool","state":{"title":"test.txt","time":{"end":1760973616232,"start":1760973616230},"input":{"filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt"},"status":"completed","output":"\n00001| tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again\n00002| \n00003| \n00004| \n","metadata":{"preview":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again\n\n\n"}},"id":"prt_a0234f463001u4vZX0ePvjr6ew","tool":"read","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"cost":0,"type":"step-finish","tokens":{"reasoning":0,"input":12949,"output":397,"cache":{"write":0,"read":12928}},"id":"prt_a0234f46800103Qi9hqHZXugdX","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973611807},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12949,"output":397,"cache":{"write":0,"read":12928}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234e31f001m4EsQdPmY3PTtS","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973611807,"completed":1760973616243},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12949,"output":397,"cache":{"write":0,"read":12928}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234e31f001m4EsQdPmY3PTtS","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973611807,"completed":1760973616244},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12949,"output":397,"cache":{"write":0,"read":12928}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234e31f001m4EsQdPmY3PTtS","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973611807,"completed":1760973616245},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12949,"output":397,"cache":{"write":0,"read":12928}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234e31f001m4EsQdPmY3PTtS","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973616258},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f482001PQbMjWc6W8s0eF","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"type":"step-start","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","id":"prt_a0234f6b0001H9XgBLZ3OdBg68","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\"","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line.","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that line","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that line.","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_a9ViHr6etx0cl2DhlyvpIsUV","type":"tool","state":{"status":"pending"},"id":"prt_a0234f9910015mW83bkeVt82ej","tool":"edit","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_a9ViHr6etx0cl2DhlyvpIsUV","type":"tool","state":{"input":{"oldString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again","filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt","newString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2"},"time":{"start":1760973617573},"status":"running"},"id":"prt_a0234f9910015mW83bkeVt82ej","tool":"edit","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"end":1760973617574,"start":1760973617574},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that line.","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"file":"/home/francis/Projects/_nvim/opencode.nvim/test.txt"},"type":"file.edited"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_a9ViHr6etx0cl2DhlyvpIsUV","type":"tool","state":{"title":"test.txt","time":{"end":1760973617583,"start":1760973617573},"input":{"oldString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again","filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt","newString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2"},"status":"completed","output":"","metadata":{"diagnostics":{},"diff":"Index: /home/francis/Projects/_nvim/opencode.nvim/test.txt\n===================================================================\n--- /home/francis/Projects/_nvim/opencode.nvim/test.txt\n+++ /home/francis/Projects/_nvim/opencode.nvim/test.txt\n@@ -1,3 +1,3 @@\n-tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2\n \n \n"}},"id":"prt_a0234f9910015mW83bkeVt82ej","tool":"edit","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"cost":0,"type":"step-finish","tokens":{"reasoning":0,"input":13077,"output":126,"cache":{"write":0,"read":12928}},"id":"prt_a0234f9af001iSzXfWH7K1FewT","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973616258},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13077,"output":126,"cache":{"write":0,"read":12928}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f482001PQbMjWc6W8s0eF","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"hash":"57d83f5596cb1f142fbc681d3d93b7184f7f73cd","type":"patch","files":["/home/francis/Projects/_nvim/opencode.nvim/test.txt"],"id":"prt_a0234f9be001oL1wchagZbSt88","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973616258,"completed":1760973617598},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13077,"output":126,"cache":{"write":0,"read":12928}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f482001PQbMjWc6W8s0eF","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973616258,"completed":1760973617600},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13077,"output":126,"cache":{"write":0,"read":12928}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f482001PQbMjWc6W8s0eF","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973616258,"completed":1760973617600},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13077,"output":126,"cache":{"write":0,"read":12928}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f482001PQbMjWc6W8s0eF","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973617606},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f9c6001JCKYaca1HHwwx6","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"type":"step-start","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","id":"prt_a0234fbf1001oojqKIBCLMQ1mp","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:**","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `again","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `again2","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `again2`","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `again2` to","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `again2` to `","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `again2` to `test","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `again2` to `test.txt","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `again2` to `test.txt`.","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"end":1760973618176,"start":1760973618176},"text":"**Done:** appended the word `again2` to `test.txt`.","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"cost":0,"type":"step-finish","tokens":{"reasoning":0,"input":13212,"output":19,"cache":{"write":0,"read":13184}},"id":"prt_a0234fc00001RTCVWXgNk2myYy","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973617606},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13212,"output":19,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f9c6001JCKYaca1HHwwx6","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973617606,"completed":1760973618194},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13212,"output":19,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f9c6001JCKYaca1HHwwx6","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973617606,"completed":1760973618199},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13212,"output":19,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f9c6001JCKYaca1HHwwx6","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973617606,"completed":1760973618199},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13212,"output":19,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f9c6001JCKYaca1HHwwx6","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0"},"type":"session.idle"},{"properties":{"info":{"id":"msg_a0236fd1c001TlwqL8fwvq529i","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973749532},"role":"user"}},"type":"message.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","text":"add another word\n","id":"prt_a0236fd1c002PcRJ8hOgqR7nte","type":"text","messageID":"msg_a0236fd1c001TlwqL8fwvq529i"}},"type":"message.part.updated"},{"properties":{"info":{"version":"0.14.6","time":{"created":1760973600383,"updated":1760973749535},"directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Adding word to test.txt"}},"type":"session.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973749591},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0236fd57001pTnTjSBdFlleCb","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"type":"step-start","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","id":"prt_a0237107b00170PEAkqhAQVD8H","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt`","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content,","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`.","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceed","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the file","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the file.","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_4Bb3eCZ89z8Ug2FSjAxY6Xr8","type":"tool","state":{"status":"pending"},"id":"prt_a023712170010ZAVXgtaS80r0m","tool":"read","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_4Bb3eCZ89z8Ug2FSjAxY6Xr8","type":"tool","state":{"input":{"filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt"},"time":{"start":1760973754916},"status":"running"},"id":"prt_a023712170010ZAVXgtaS80r0m","tool":"read","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"end":1760973754916,"start":1760973754916},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the file.","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_4Bb3eCZ89z8Ug2FSjAxY6Xr8","type":"tool","state":{"title":"test.txt","time":{"end":1760973754918,"start":1760973754916},"input":{"filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt"},"status":"completed","output":"\n00001| tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2\n00002| \n00003| \n00004| \n","metadata":{"preview":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2\n\n\n"}},"id":"prt_a023712170010ZAVXgtaS80r0m","tool":"read","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"cost":0,"type":"step-finish","tokens":{"reasoning":0,"input":13241,"output":457,"cache":{"write":0,"read":13184}},"id":"prt_a02371226001LxXIRETdzHQDxW","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973749591},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13241,"output":457,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0236fd57001pTnTjSBdFlleCb","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973749591,"completed":1760973754931},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13241,"output":457,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0236fd57001pTnTjSBdFlleCb","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973749591,"completed":1760973754933},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13241,"output":457,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0236fd57001pTnTjSBdFlleCb","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973749591,"completed":1760973754934},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13241,"output":457,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0236fd57001pTnTjSBdFlleCb","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973754945},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a02371241001PBQAsr8Oc9hqNI","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"type":"step-start","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","id":"prt_a02371fcf001QAGd8I3AJYcZQW","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\"","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt`","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit.","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change now","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change now.","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_2GJo632y9iJGpf7eE5seXx0j","type":"tool","state":{"status":"pending"},"id":"prt_a02372387001SiuePn07aa1VNC","tool":"edit","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_2GJo632y9iJGpf7eE5seXx0j","type":"tool","state":{"input":{"oldString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2","filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt","newString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3"},"time":{"start":1760973759397},"status":"running"},"id":"prt_a02372387001SiuePn07aa1VNC","tool":"edit","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"end":1760973759398,"start":1760973759398},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change now.","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"file":"/home/francis/Projects/_nvim/opencode.nvim/test.txt"},"type":"file.edited"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_2GJo632y9iJGpf7eE5seXx0j","type":"tool","state":{"title":"test.txt","time":{"end":1760973759413,"start":1760973759397},"input":{"oldString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2","filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt","newString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3"},"status":"completed","output":"","metadata":{"diagnostics":{},"diff":"Index: /home/francis/Projects/_nvim/opencode.nvim/test.txt\n===================================================================\n--- /home/francis/Projects/_nvim/opencode.nvim/test.txt\n+++ /home/francis/Projects/_nvim/opencode.nvim/test.txt\n@@ -1,3 +1,3 @@\n-tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3\n \n \n"}},"id":"prt_a02372387001SiuePn07aa1VNC","tool":"edit","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"cost":0,"type":"step-finish","tokens":{"reasoning":0,"input":13367,"output":459,"cache":{"write":0,"read":13184}},"id":"prt_a023723b6001LJ3f2pxz1bIYRy","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973754945},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13367,"output":459,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a02371241001PBQAsr8Oc9hqNI","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"hash":"d988cc85565b99017d40ad8baea20225165be9d5","type":"patch","files":["/home/francis/Projects/_nvim/opencode.nvim/test.txt"],"id":"prt_a023723c4001SR03K7sDnOvQ21","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973754945,"completed":1760973759429},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13367,"output":459,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a02371241001PBQAsr8Oc9hqNI","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973754945,"completed":1760973759430},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13367,"output":459,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a02371241001PBQAsr8Oc9hqNI","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973754945,"completed":1760973759431},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13367,"output":459,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a02371241001PBQAsr8Oc9hqNI","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973759440},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a023723d0001r87MaJThFssUw1","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"type":"step-start","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","id":"prt_a02372664001tXq2uEhOCcXuDe","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:**","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `again","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `again3","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `again3`","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `again3` to","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `again3` to `","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `again3` to `test","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `again3` to `test.txt","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `again3` to `test.txt`.","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"end":1760973760125,"start":1760973760125},"text":"**Done:** appended the word `again3` to `test.txt`.","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"cost":0,"type":"step-finish","tokens":{"reasoning":0,"input":13509,"output":19,"cache":{"write":0,"read":13312}},"id":"prt_a0237267e001nad2YARrEmo6hb","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973759440},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13509,"output":19,"cache":{"write":0,"read":13312}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a023723d0001r87MaJThFssUw1","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973759440,"completed":1760973760142},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13509,"output":19,"cache":{"write":0,"read":13312}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a023723d0001r87MaJThFssUw1","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973759440,"completed":1760973760147},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13509,"output":19,"cache":{"write":0,"read":13312}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a023723d0001r87MaJThFssUw1","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973759440,"completed":1760973760148},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13509,"output":19,"cache":{"write":0,"read":13312}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a023723d0001r87MaJThFssUw1","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0"},"type":"session.idle"},{"properties":{"info":{"version":"0.14.6","time":{"created":1760973600383,"updated":1760978265898},"directory":"/home/francis/Projects/_nvim/opencode.nvim","revert":{"diff":"diff --git a/test.txt b/test.txt\nindex 7191e44..f2caa07 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,3 +1,3 @@\n- tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2","snapshot":"281b11ee830296ddff05bf14d0d7b9ef4b1ac8af","messageID":"msg_a0236fd1c001TlwqL8fwvq529i"},"id":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Adding word to test.txt"}},"type":"session.updated"},{"properties":{"info":{"version":"0.14.6","time":{"created":1760973600383,"updated":1760978268997},"directory":"/home/francis/Projects/_nvim/opencode.nvim","revert":{"diff":"diff --git a/test.txt b/test.txt\nindex 7191e44..387f18d 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,3 +1,3 @@\n- tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again","snapshot":"281b11ee830296ddff05bf14d0d7b9ef4b1ac8af","messageID":"msg_a0234e308001SKl5bQUibp5gtI"},"id":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Adding word to test.txt"}},"type":"session.updated"},{"properties":{"info":{"version":"0.14.6","time":{"created":1760973600383,"updated":1760978282075},"directory":"/home/francis/Projects/_nvim/opencode.nvim","revert":{"diff":"diff --git a/test.txt b/test.txt\nindex 7191e44..f2caa07 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,3 +1,3 @@\n- tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2","snapshot":"281b11ee830296ddff05bf14d0d7b9ef4b1ac8af","messageID":"msg_a0236fd1c001TlwqL8fwvq529i"},"id":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Adding word to test.txt"}},"type":"session.updated"},{"properties":{"info":{"version":"0.14.6","time":{"created":1760973600383,"updated":1760978577423},"directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Adding word to test.txt"}},"type":"session.updated"}]
+[
+ { "properties": {}, "type": "server.connected" },
+ {
+ "properties": {
+ "info": {
+ "id": "msg_a0234c0b7001y2o9S1jMaNVZar",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973602999 },
+ "role": "user"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "text": "add another word\n",
+ "id": "prt_a0234c0b8001E8tvDdVNT0NiFh",
+ "type": "text",
+ "messageID": "msg_a0234c0b7001y2o9S1jMaNVZar"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "synthetic": true,
+ "type": "text",
+ "text": "Called the Read tool with the following input: {\"filePath\":\"/home/francis/Projects/_nvim/opencode.nvim/test.txt\"}",
+ "id": "prt_a0234c0ba001p2wDCCzgtdcf9g",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c0b7001y2o9S1jMaNVZar"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "synthetic": true,
+ "type": "text",
+ "text": "\n00001| tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more\n00002| \n00003| \n00004| \n",
+ "id": "prt_a0234c0ba002ifWGZD21JdnYs6",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c0b7001y2o9S1jMaNVZar"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "type": "file",
+ "url": "file:///home/francis/Projects/_nvim/opencode.nvim/test.txt",
+ "mime": "text/plain",
+ "id": "prt_a0234c0ba003rwMIYGQq901md0",
+ "filename": "test.txt",
+ "messageID": "msg_a0234c0b7001y2o9S1jMaNVZar"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "version": "0.14.6",
+ "time": { "created": 1760973600383, "updated": 1760973603008 },
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "title": "New session - 2025-10-20T15:20:00.383Z"
+ }
+ },
+ "type": "session.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973604758 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234c7960011LTxTvD94hfWCi",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "version": "0.14.6",
+ "time": { "created": 1760973600383, "updated": 1760973605391 },
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "title": "Adding word to test.txt"
+ }
+ },
+ "type": "session.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "id": "prt_a0234d6050012gZEes0qoo3vws",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\")",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`.",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line now",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line now.",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_f5xkch2vMvn01ko5Ko4GzNbL",
+ "type": "tool",
+ "state": { "status": "pending" },
+ "id": "prt_a0234d89c001EJCQkv3qyPNYjc",
+ "tool": "edit",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_f5xkch2vMvn01ko5Ko4GzNbL",
+ "type": "tool",
+ "state": {
+ "input": {
+ "oldString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more",
+ "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt",
+ "newString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again"
+ },
+ "time": { "start": 1760973609159 },
+ "status": "running"
+ },
+ "id": "prt_a0234d89c001EJCQkv3qyPNYjc",
+ "tool": "edit",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": { "file": "/home/francis/Projects/_nvim/opencode.nvim/test.txt" }, "type": "file.edited" },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_f5xkch2vMvn01ko5Ko4GzNbL",
+ "type": "tool",
+ "state": {
+ "title": "test.txt",
+ "time": { "end": 1760973609163, "start": 1760973609159 },
+ "input": {
+ "oldString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more",
+ "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt",
+ "newString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again"
+ },
+ "status": "completed",
+ "output": "",
+ "metadata": {
+ "diagnostics": {},
+ "diff": "Index: /home/francis/Projects/_nvim/opencode.nvim/test.txt\n===================================================================\n--- /home/francis/Projects/_nvim/opencode.nvim/test.txt\n+++ /home/francis/Projects/_nvim/opencode.nvim/test.txt\n@@ -1,3 +1,3 @@\n-tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again\n \n \n"
+ }
+ },
+ "id": "prt_a0234d89c001EJCQkv3qyPNYjc",
+ "tool": "edit",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "end": 1760973609181, "start": 1760973609181 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line now.",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "cost": 0,
+ "type": "step-finish",
+ "tokens": { "reasoning": 0, "input": 12788, "output": 514, "cache": { "write": 0, "read": 7168 } },
+ "id": "prt_a0234d8df001tlclk7glXfU1WC",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973604758 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12788, "output": 514, "cache": { "write": 0, "read": 7168 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234c7960011LTxTvD94hfWCi",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "hash": "1b6ba655c6c0d899965adff278ac6320d5fc3b12",
+ "type": "patch",
+ "files": ["/home/francis/Projects/_nvim/opencode.nvim/test.txt"],
+ "id": "prt_a0234d8f0001GsHhf2mPuESk1p",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973604758, "completed": 1760973609201 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12788, "output": 514, "cache": { "write": 0, "read": 7168 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234c7960011LTxTvD94hfWCi",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973604758, "completed": 1760973609207 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12788, "output": 514, "cache": { "write": 0, "read": 7168 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234c7960011LTxTvD94hfWCi",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973604758, "completed": 1760973609207 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12788, "output": 514, "cache": { "write": 0, "read": 7168 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234c7960011LTxTvD94hfWCi",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973609211 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234d8fb001SXyngLjuKSuxOY",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "id": "prt_a0234dbf00016c9aOHUxpQxM0U",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:**",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word `",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word `again",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word `again`",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word `again` to",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word `again` to `",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word `again` to `test",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word `again` to `test.txt",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word `again` to `test.txt`.",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "end": 1760973609987, "start": 1760973609987 },
+ "text": "**Done:** added the word `again` to `test.txt`.",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "cost": 0,
+ "type": "step-finish",
+ "tokens": { "reasoning": 0, "input": 12921, "output": 18, "cache": { "write": 0, "read": 12672 } },
+ "id": "prt_a0234dc03001iO2ubPxctfhnkY",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973609211 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12921, "output": 18, "cache": { "write": 0, "read": 12672 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234d8fb001SXyngLjuKSuxOY",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973609211, "completed": 1760973610000 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12921, "output": 18, "cache": { "write": 0, "read": 12672 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234d8fb001SXyngLjuKSuxOY",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973609211, "completed": 1760973610001 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12921, "output": 18, "cache": { "write": 0, "read": 12672 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234d8fb001SXyngLjuKSuxOY",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973609211, "completed": 1760973610002 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12921, "output": 18, "cache": { "write": 0, "read": 12672 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234d8fb001SXyngLjuKSuxOY",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ { "properties": { "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0" }, "type": "session.idle" },
+ {
+ "properties": {
+ "info": {
+ "id": "msg_a0234e308001SKl5bQUibp5gtI",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973611784 },
+ "role": "user"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "text": "add another word\n",
+ "id": "prt_a0234e308002nvLNQpQkMykslq",
+ "type": "text",
+ "messageID": "msg_a0234e308001SKl5bQUibp5gtI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "version": "0.14.6",
+ "time": { "created": 1760973600383, "updated": 1760973611785 },
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "title": "Adding word to test.txt"
+ }
+ },
+ "type": "session.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973611807 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234e31f001m4EsQdPmY3PTtS",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "id": "prt_a0234f2d9001o5Ev43oSWT3Wum",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt`",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content,",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\")",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line.",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceed",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the file",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the file.",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_YtG0tPTwncFNNWTaUP6XeTAe",
+ "type": "tool",
+ "state": { "status": "pending" },
+ "id": "prt_a0234f463001u4vZX0ePvjr6ew",
+ "tool": "read",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_YtG0tPTwncFNNWTaUP6XeTAe",
+ "type": "tool",
+ "state": {
+ "input": { "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt" },
+ "time": { "start": 1760973616230 },
+ "status": "running"
+ },
+ "id": "prt_a0234f463001u4vZX0ePvjr6ew",
+ "tool": "read",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "end": 1760973616230, "start": 1760973616230 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the file.",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_YtG0tPTwncFNNWTaUP6XeTAe",
+ "type": "tool",
+ "state": {
+ "title": "test.txt",
+ "time": { "end": 1760973616232, "start": 1760973616230 },
+ "input": { "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt" },
+ "status": "completed",
+ "output": "\n00001| tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again\n00002| \n00003| \n00004| \n",
+ "metadata": {
+ "preview": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again\n\n\n"
+ }
+ },
+ "id": "prt_a0234f463001u4vZX0ePvjr6ew",
+ "tool": "read",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "cost": 0,
+ "type": "step-finish",
+ "tokens": { "reasoning": 0, "input": 12949, "output": 397, "cache": { "write": 0, "read": 12928 } },
+ "id": "prt_a0234f46800103Qi9hqHZXugdX",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973611807 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12949, "output": 397, "cache": { "write": 0, "read": 12928 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234e31f001m4EsQdPmY3PTtS",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973611807, "completed": 1760973616243 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12949, "output": 397, "cache": { "write": 0, "read": 12928 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234e31f001m4EsQdPmY3PTtS",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973611807, "completed": 1760973616244 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12949, "output": 397, "cache": { "write": 0, "read": 12928 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234e31f001m4EsQdPmY3PTtS",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973611807, "completed": 1760973616245 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12949, "output": 397, "cache": { "write": 0, "read": 12928 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234e31f001m4EsQdPmY3PTtS",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973616258 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f482001PQbMjWc6W8s0eF",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "id": "prt_a0234f6b0001H9XgBLZ3OdBg68",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\"",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line.",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that line",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that line.",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_a9ViHr6etx0cl2DhlyvpIsUV",
+ "type": "tool",
+ "state": { "status": "pending" },
+ "id": "prt_a0234f9910015mW83bkeVt82ej",
+ "tool": "edit",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_a9ViHr6etx0cl2DhlyvpIsUV",
+ "type": "tool",
+ "state": {
+ "input": {
+ "oldString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again",
+ "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt",
+ "newString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2"
+ },
+ "time": { "start": 1760973617573 },
+ "status": "running"
+ },
+ "id": "prt_a0234f9910015mW83bkeVt82ej",
+ "tool": "edit",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "end": 1760973617574, "start": 1760973617574 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that line.",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": { "file": "/home/francis/Projects/_nvim/opencode.nvim/test.txt" }, "type": "file.edited" },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_a9ViHr6etx0cl2DhlyvpIsUV",
+ "type": "tool",
+ "state": {
+ "title": "test.txt",
+ "time": { "end": 1760973617583, "start": 1760973617573 },
+ "input": {
+ "oldString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again",
+ "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt",
+ "newString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2"
+ },
+ "status": "completed",
+ "output": "",
+ "metadata": {
+ "diagnostics": {},
+ "diff": "Index: /home/francis/Projects/_nvim/opencode.nvim/test.txt\n===================================================================\n--- /home/francis/Projects/_nvim/opencode.nvim/test.txt\n+++ /home/francis/Projects/_nvim/opencode.nvim/test.txt\n@@ -1,3 +1,3 @@\n-tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2\n \n \n"
+ }
+ },
+ "id": "prt_a0234f9910015mW83bkeVt82ej",
+ "tool": "edit",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "cost": 0,
+ "type": "step-finish",
+ "tokens": { "reasoning": 0, "input": 13077, "output": 126, "cache": { "write": 0, "read": 12928 } },
+ "id": "prt_a0234f9af001iSzXfWH7K1FewT",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973616258 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13077, "output": 126, "cache": { "write": 0, "read": 12928 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f482001PQbMjWc6W8s0eF",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "hash": "57d83f5596cb1f142fbc681d3d93b7184f7f73cd",
+ "type": "patch",
+ "files": ["/home/francis/Projects/_nvim/opencode.nvim/test.txt"],
+ "id": "prt_a0234f9be001oL1wchagZbSt88",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973616258, "completed": 1760973617598 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13077, "output": 126, "cache": { "write": 0, "read": 12928 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f482001PQbMjWc6W8s0eF",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973616258, "completed": 1760973617600 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13077, "output": 126, "cache": { "write": 0, "read": 12928 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f482001PQbMjWc6W8s0eF",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973616258, "completed": 1760973617600 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13077, "output": 126, "cache": { "write": 0, "read": 12928 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f482001PQbMjWc6W8s0eF",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973617606 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f9c6001JCKYaca1HHwwx6",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "id": "prt_a0234fbf1001oojqKIBCLMQ1mp",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:**",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `again",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `again2",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `again2`",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `again2` to",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `again2` to `",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `again2` to `test",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `again2` to `test.txt",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `again2` to `test.txt`.",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "end": 1760973618176, "start": 1760973618176 },
+ "text": "**Done:** appended the word `again2` to `test.txt`.",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "cost": 0,
+ "type": "step-finish",
+ "tokens": { "reasoning": 0, "input": 13212, "output": 19, "cache": { "write": 0, "read": 13184 } },
+ "id": "prt_a0234fc00001RTCVWXgNk2myYy",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973617606 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13212, "output": 19, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f9c6001JCKYaca1HHwwx6",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973617606, "completed": 1760973618194 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13212, "output": 19, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f9c6001JCKYaca1HHwwx6",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973617606, "completed": 1760973618199 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13212, "output": 19, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f9c6001JCKYaca1HHwwx6",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973617606, "completed": 1760973618199 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13212, "output": 19, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f9c6001JCKYaca1HHwwx6",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ { "properties": { "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0" }, "type": "session.idle" },
+ {
+ "properties": {
+ "info": {
+ "id": "msg_a0236fd1c001TlwqL8fwvq529i",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973749532 },
+ "role": "user"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "text": "add another word\n",
+ "id": "prt_a0236fd1c002PcRJ8hOgqR7nte",
+ "type": "text",
+ "messageID": "msg_a0236fd1c001TlwqL8fwvq529i"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "version": "0.14.6",
+ "time": { "created": 1760973600383, "updated": 1760973749535 },
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "title": "Adding word to test.txt"
+ }
+ },
+ "type": "session.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973749591 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0236fd57001pTnTjSBdFlleCb",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "id": "prt_a0237107b00170PEAkqhAQVD8H",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt`",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content,",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`.",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceed",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the file",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the file.",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_4Bb3eCZ89z8Ug2FSjAxY6Xr8",
+ "type": "tool",
+ "state": { "status": "pending" },
+ "id": "prt_a023712170010ZAVXgtaS80r0m",
+ "tool": "read",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_4Bb3eCZ89z8Ug2FSjAxY6Xr8",
+ "type": "tool",
+ "state": {
+ "input": { "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt" },
+ "time": { "start": 1760973754916 },
+ "status": "running"
+ },
+ "id": "prt_a023712170010ZAVXgtaS80r0m",
+ "tool": "read",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "end": 1760973754916, "start": 1760973754916 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the file.",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_4Bb3eCZ89z8Ug2FSjAxY6Xr8",
+ "type": "tool",
+ "state": {
+ "title": "test.txt",
+ "time": { "end": 1760973754918, "start": 1760973754916 },
+ "input": { "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt" },
+ "status": "completed",
+ "output": "\n00001| tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2\n00002| \n00003| \n00004| \n",
+ "metadata": {
+ "preview": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2\n\n\n"
+ }
+ },
+ "id": "prt_a023712170010ZAVXgtaS80r0m",
+ "tool": "read",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "cost": 0,
+ "type": "step-finish",
+ "tokens": { "reasoning": 0, "input": 13241, "output": 457, "cache": { "write": 0, "read": 13184 } },
+ "id": "prt_a02371226001LxXIRETdzHQDxW",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973749591 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13241, "output": 457, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0236fd57001pTnTjSBdFlleCb",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973749591, "completed": 1760973754931 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13241, "output": 457, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0236fd57001pTnTjSBdFlleCb",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973749591, "completed": 1760973754933 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13241, "output": 457, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0236fd57001pTnTjSBdFlleCb",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973749591, "completed": 1760973754934 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13241, "output": 457, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0236fd57001pTnTjSBdFlleCb",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973754945 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a02371241001PBQAsr8Oc9hqNI",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "id": "prt_a02371fcf001QAGd8I3AJYcZQW",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\"",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt`",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit.",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change now",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change now.",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_2GJo632y9iJGpf7eE5seXx0j",
+ "type": "tool",
+ "state": { "status": "pending" },
+ "id": "prt_a02372387001SiuePn07aa1VNC",
+ "tool": "edit",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_2GJo632y9iJGpf7eE5seXx0j",
+ "type": "tool",
+ "state": {
+ "input": {
+ "oldString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2",
+ "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt",
+ "newString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3"
+ },
+ "time": { "start": 1760973759397 },
+ "status": "running"
+ },
+ "id": "prt_a02372387001SiuePn07aa1VNC",
+ "tool": "edit",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "end": 1760973759398, "start": 1760973759398 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change now.",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": { "file": "/home/francis/Projects/_nvim/opencode.nvim/test.txt" }, "type": "file.edited" },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_2GJo632y9iJGpf7eE5seXx0j",
+ "type": "tool",
+ "state": {
+ "title": "test.txt",
+ "time": { "end": 1760973759413, "start": 1760973759397 },
+ "input": {
+ "oldString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2",
+ "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt",
+ "newString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3"
+ },
+ "status": "completed",
+ "output": "",
+ "metadata": {
+ "diagnostics": {},
+ "diff": "Index: /home/francis/Projects/_nvim/opencode.nvim/test.txt\n===================================================================\n--- /home/francis/Projects/_nvim/opencode.nvim/test.txt\n+++ /home/francis/Projects/_nvim/opencode.nvim/test.txt\n@@ -1,3 +1,3 @@\n-tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3\n \n \n"
+ }
+ },
+ "id": "prt_a02372387001SiuePn07aa1VNC",
+ "tool": "edit",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "cost": 0,
+ "type": "step-finish",
+ "tokens": { "reasoning": 0, "input": 13367, "output": 459, "cache": { "write": 0, "read": 13184 } },
+ "id": "prt_a023723b6001LJ3f2pxz1bIYRy",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973754945 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13367, "output": 459, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a02371241001PBQAsr8Oc9hqNI",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "hash": "d988cc85565b99017d40ad8baea20225165be9d5",
+ "type": "patch",
+ "files": ["/home/francis/Projects/_nvim/opencode.nvim/test.txt"],
+ "id": "prt_a023723c4001SR03K7sDnOvQ21",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973754945, "completed": 1760973759429 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13367, "output": 459, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a02371241001PBQAsr8Oc9hqNI",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973754945, "completed": 1760973759430 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13367, "output": 459, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a02371241001PBQAsr8Oc9hqNI",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973754945, "completed": 1760973759431 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13367, "output": 459, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a02371241001PBQAsr8Oc9hqNI",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973759440 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a023723d0001r87MaJThFssUw1",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "id": "prt_a02372664001tXq2uEhOCcXuDe",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:**",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `again",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `again3",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `again3`",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `again3` to",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `again3` to `",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `again3` to `test",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `again3` to `test.txt",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `again3` to `test.txt`.",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "end": 1760973760125, "start": 1760973760125 },
+ "text": "**Done:** appended the word `again3` to `test.txt`.",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "cost": 0,
+ "type": "step-finish",
+ "tokens": { "reasoning": 0, "input": 13509, "output": 19, "cache": { "write": 0, "read": 13312 } },
+ "id": "prt_a0237267e001nad2YARrEmo6hb",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973759440 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13509, "output": 19, "cache": { "write": 0, "read": 13312 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a023723d0001r87MaJThFssUw1",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973759440, "completed": 1760973760142 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13509, "output": 19, "cache": { "write": 0, "read": 13312 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a023723d0001r87MaJThFssUw1",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973759440, "completed": 1760973760147 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13509, "output": 19, "cache": { "write": 0, "read": 13312 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a023723d0001r87MaJThFssUw1",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973759440, "completed": 1760973760148 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13509, "output": 19, "cache": { "write": 0, "read": 13312 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a023723d0001r87MaJThFssUw1",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ { "properties": { "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0" }, "type": "session.idle" },
+ {
+ "properties": {
+ "info": {
+ "version": "0.14.6",
+ "time": { "created": 1760973600383, "updated": 1760978265898 },
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "revert": {
+ "diff": "diff --git a/test.txt b/test.txt\nindex 7191e44..f2caa07 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,3 +1,3 @@\n- tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2",
+ "snapshot": "281b11ee830296ddff05bf14d0d7b9ef4b1ac8af",
+ "messageID": "msg_a0236fd1c001TlwqL8fwvq529i"
+ },
+ "id": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "title": "Adding word to test.txt"
+ }
+ },
+ "type": "session.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "version": "0.14.6",
+ "time": { "created": 1760973600383, "updated": 1760978268997 },
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "revert": {
+ "diff": "diff --git a/test.txt b/test.txt\nindex 7191e44..387f18d 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,3 +1,3 @@\n- tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again",
+ "snapshot": "281b11ee830296ddff05bf14d0d7b9ef4b1ac8af",
+ "messageID": "msg_a0234e308001SKl5bQUibp5gtI"
+ },
+ "id": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "title": "Adding word to test.txt"
+ }
+ },
+ "type": "session.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "version": "0.14.6",
+ "time": { "created": 1760973600383, "updated": 1760978282075 },
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "revert": {
+ "diff": "diff --git a/test.txt b/test.txt\nindex 7191e44..f2caa07 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,3 +1,3 @@\n- tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2",
+ "snapshot": "281b11ee830296ddff05bf14d0d7b9ef4b1ac8af",
+ "messageID": "msg_a0236fd1c001TlwqL8fwvq529i"
+ },
+ "id": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "title": "Adding word to test.txt"
+ }
+ },
+ "type": "session.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "version": "0.14.6",
+ "time": { "created": 1760973600383, "updated": 1760978577423 },
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "title": "Adding word to test.txt"
+ }
+ },
+ "type": "session.updated"
+ }
+]
diff --git a/tests/data/redo-once.expected.json b/tests/data/redo-once.expected.json
index ab2b8344..71f26d3f 100644
--- a/tests/data/redo-once.expected.json
+++ b/tests/data/redo-once.expected.json
@@ -1 +1,1047 @@
-{"actions":[{"text":"[R]evert file","args":["57d83f5596cb1f142fbc681d3d93b7184f7f73cd"],"display_line":56,"key":"R","range":{"to":56,"from":56},"type":"diff_revert_selected_file"},{"text":"Revert [A]ll","args":["57d83f5596cb1f142fbc681d3d93b7184f7f73cd"],"display_line":56,"key":"A","range":{"to":56,"from":56},"type":"diff_revert_all"},{"text":"[D]iff","args":["57d83f5596cb1f142fbc681d3d93b7184f7f73cd"],"display_line":56,"key":"D","range":{"to":56,"from":56},"type":"diff_open"},{"text":"[R]evert file","args":["1b6ba655c6c0d899965adff278ac6320d5fc3b12"],"display_line":22,"key":"R","range":{"to":22,"from":22},"type":"diff_revert_selected_file"},{"text":"Revert [A]ll","args":["1b6ba655c6c0d899965adff278ac6320d5fc3b12"],"display_line":22,"key":"A","range":{"to":22,"from":22},"type":"diff_revert_all"},{"text":"[D]iff","args":["1b6ba655c6c0d899965adff278ac6320d5fc3b12"],"display_line":22,"key":"D","range":{"to":22,"from":22},"type":"diff_open"}],"extmarks":[[1,1,0,{"priority":10,"virt_text_win_col":-3,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-20 15:20:02)","OpencodeHint"],[" [msg_a0234c0b7001y2o9S1jMaNVZar]","OpencodeHint"]],"right_gravity":true,"virt_text_repeat_linebreak":false}],[2,2,0,{"priority":4096,"virt_text_win_col":-3,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[3,3,0,{"priority":4096,"virt_text_win_col":-3,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[4,4,0,{"priority":4096,"virt_text_win_col":-3,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[5,5,0,{"priority":4096,"virt_text_win_col":-3,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[6,8,0,{"priority":10,"virt_text_win_col":-3,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-5-mini","OpencodeHint"],[" (2025-10-20 15:20:04)","OpencodeHint"],[" [msg_a0234c7960011LTxTvD94hfWCi]","OpencodeHint"]],"right_gravity":true,"virt_text_repeat_linebreak":false}],[7,12,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[8,13,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[9,14,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[10,15,0,{"end_col":0,"end_row":16,"virt_text_pos":"overlay","virt_text_hide":false,"hl_group":"OpencodeDiffDelete","priority":5000,"ns_id":3,"hl_eol":true,"end_right_gravity":false,"virt_text":[["-","OpencodeDiffDelete"]],"right_gravity":true,"virt_text_repeat_linebreak":false}],[11,15,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[12,16,0,{"end_col":0,"end_row":17,"virt_text_pos":"overlay","virt_text_hide":false,"hl_group":"OpencodeDiffAdd","priority":5000,"ns_id":3,"hl_eol":true,"end_right_gravity":false,"virt_text":[["+","OpencodeDiffAdd"]],"right_gravity":true,"virt_text_repeat_linebreak":false}],[13,16,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[14,17,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[15,18,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[16,19,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[17,20,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[18,25,0,{"priority":10,"virt_text_win_col":-3,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-5-mini","OpencodeHint"],[" (2025-10-20 15:20:09)","OpencodeHint"],[" [msg_a0234d8fb001SXyngLjuKSuxOY]","OpencodeHint"]],"right_gravity":true,"virt_text_repeat_linebreak":false}],[19,30,0,{"priority":10,"virt_text_win_col":-3,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-20 15:20:11)","OpencodeHint"],[" [msg_a0234e308001SKl5bQUibp5gtI]","OpencodeHint"]],"right_gravity":true,"virt_text_repeat_linebreak":false}],[20,31,0,{"priority":4096,"virt_text_win_col":-3,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[21,32,0,{"priority":4096,"virt_text_win_col":-3,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[22,35,0,{"priority":10,"virt_text_win_col":-3,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-5-mini","OpencodeHint"],[" (2025-10-20 15:20:11)","OpencodeHint"],[" [msg_a0234e31f001m4EsQdPmY3PTtS]","OpencodeHint"]],"right_gravity":true,"virt_text_repeat_linebreak":false}],[23,42,0,{"priority":10,"virt_text_win_col":-3,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-5-mini","OpencodeHint"],[" (2025-10-20 15:20:16)","OpencodeHint"],[" [msg_a0234f482001PQbMjWc6W8s0eF]","OpencodeHint"]],"right_gravity":true,"virt_text_repeat_linebreak":false}],[24,46,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[25,47,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[26,48,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[27,49,0,{"end_col":0,"end_row":50,"virt_text_pos":"overlay","virt_text_hide":false,"hl_group":"OpencodeDiffDelete","priority":5000,"ns_id":3,"hl_eol":true,"end_right_gravity":false,"virt_text":[["-","OpencodeDiffDelete"]],"right_gravity":true,"virt_text_repeat_linebreak":false}],[28,49,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[29,50,0,{"end_col":0,"end_row":51,"virt_text_pos":"overlay","virt_text_hide":false,"hl_group":"OpencodeDiffAdd","priority":5000,"ns_id":3,"hl_eol":true,"end_right_gravity":false,"virt_text":[["+","OpencodeDiffAdd"]],"right_gravity":true,"virt_text_repeat_linebreak":false}],[30,50,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[31,51,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[32,52,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[33,53,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[34,54,0,{"priority":4096,"virt_text_win_col":-1,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"virt_text_repeat_linebreak":true}],[35,59,0,{"priority":10,"virt_text_win_col":-3,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-5-mini","OpencodeHint"],[" (2025-10-20 15:20:17)","OpencodeHint"],[" [msg_a0234f9c6001JCKYaca1HHwwx6]","OpencodeHint"]],"right_gravity":true,"virt_text_repeat_linebreak":false}],[36,69,0,{"priority":1000,"virt_text_win_col":12,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["+1","OpencodeDiffAddText"]],"right_gravity":true,"virt_text_repeat_linebreak":false}],[37,69,0,{"priority":1000,"virt_text_win_col":15,"ns_id":3,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text":[["-1","OpencodeDiffDeleteText"]],"right_gravity":true,"virt_text_repeat_linebreak":false}]],"lines":["----","","","add another word","","[`test.txt`](test.txt)","","----","","","I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line now.","","** edit** `/home/francis/Projects/_nvim/opencode.nvim/test.txt`","","`````txt"," tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more"," tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again"," "," ","","`````","","** Created Snapshot** `1b6ba655`","","----","","","**Done:** added the word `again` to `test.txt`.","","----","","","add another word","","----","","","I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the file.","","** read** `/home/francis/Projects/_nvim/opencode.nvim/test.txt`","","----","","","Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that line.","","** edit** `/home/francis/Projects/_nvim/opencode.nvim/test.txt`","","`````txt"," tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again"," tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2"," "," ","","`````","","** Created Snapshot** `57d83f55`","","----","","","**Done:** appended the word `again2` to `test.txt`.","","----","","> 1 message reverted, 2 tool calls reverted",">","> type `/redo` to restore.",""," test.txt: +1 -1",""],"timestamp":1769172261}
+{
+ "actions": [
+ {
+ "args": [
+ "57d83f5596cb1f142fbc681d3d93b7184f7f73cd"
+ ],
+ "display_line": 56,
+ "key": "R",
+ "range": {
+ "from": 56,
+ "to": 56
+ },
+ "text": "[R]evert file",
+ "type": "diff_revert_selected_file"
+ },
+ {
+ "args": [
+ "57d83f5596cb1f142fbc681d3d93b7184f7f73cd"
+ ],
+ "display_line": 56,
+ "key": "A",
+ "range": {
+ "from": 56,
+ "to": 56
+ },
+ "text": "Revert [A]ll",
+ "type": "diff_revert_all"
+ },
+ {
+ "args": [
+ "57d83f5596cb1f142fbc681d3d93b7184f7f73cd"
+ ],
+ "display_line": 56,
+ "key": "D",
+ "range": {
+ "from": 56,
+ "to": 56
+ },
+ "text": "[D]iff",
+ "type": "diff_open"
+ },
+ {
+ "args": [
+ "1b6ba655c6c0d899965adff278ac6320d5fc3b12"
+ ],
+ "display_line": 22,
+ "key": "R",
+ "range": {
+ "from": 22,
+ "to": 22
+ },
+ "text": "[R]evert file",
+ "type": "diff_revert_selected_file"
+ },
+ {
+ "args": [
+ "1b6ba655c6c0d899965adff278ac6320d5fc3b12"
+ ],
+ "display_line": 22,
+ "key": "A",
+ "range": {
+ "from": 22,
+ "to": 22
+ },
+ "text": "Revert [A]ll",
+ "type": "diff_revert_all"
+ },
+ {
+ "args": [
+ "1b6ba655c6c0d899965adff278ac6320d5fc3b12"
+ ],
+ "display_line": 22,
+ "key": "D",
+ "range": {
+ "from": 22,
+ "to": 22
+ },
+ "text": "[D]iff",
+ "type": "diff_open"
+ }
+ ],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:20:02)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a0234c0b7001y2o9S1jMaNVZar]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 2,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 3,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 4,
+ 4,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 5,
+ 5,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 6,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-5-mini",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:20:04)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a0234c7960011LTxTvD94hfWCi]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 7,
+ 12,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 8,
+ 13,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 9,
+ 14,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 10,
+ 15,
+ 0,
+ {
+ "end_col": 0,
+ "end_right_gravity": false,
+ "end_row": 16,
+ "hl_eol": true,
+ "hl_group": "OpencodeDiffDelete",
+ "ns_id": 3,
+ "priority": 5000,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "-",
+ "OpencodeDiffDelete"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "overlay",
+ "virt_text_repeat_linebreak": false
+ }
+ ],
+ [
+ 11,
+ 15,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 12,
+ 16,
+ 0,
+ {
+ "end_col": 0,
+ "end_right_gravity": false,
+ "end_row": 17,
+ "hl_eol": true,
+ "hl_group": "OpencodeDiffAdd",
+ "ns_id": 3,
+ "priority": 5000,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "+",
+ "OpencodeDiffAdd"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "overlay",
+ "virt_text_repeat_linebreak": false
+ }
+ ],
+ [
+ 13,
+ 16,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 14,
+ 17,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 15,
+ 18,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 16,
+ 19,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 17,
+ 20,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 18,
+ 25,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-5-mini",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:20:09)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a0234d8fb001SXyngLjuKSuxOY]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 19,
+ 30,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:20:11)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a0234e308001SKl5bQUibp5gtI]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 20,
+ 31,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 21,
+ 32,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 22,
+ 35,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-5-mini",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:20:11)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a0234e31f001m4EsQdPmY3PTtS]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 23,
+ 42,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-5-mini",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:20:16)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a0234f482001PQbMjWc6W8s0eF]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 24,
+ 46,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 25,
+ 47,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 26,
+ 48,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 27,
+ 49,
+ 0,
+ {
+ "end_col": 0,
+ "end_right_gravity": false,
+ "end_row": 50,
+ "hl_eol": true,
+ "hl_group": "OpencodeDiffDelete",
+ "ns_id": 3,
+ "priority": 5000,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "-",
+ "OpencodeDiffDelete"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "overlay",
+ "virt_text_repeat_linebreak": false
+ }
+ ],
+ [
+ 28,
+ 49,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 29,
+ 50,
+ 0,
+ {
+ "end_col": 0,
+ "end_right_gravity": false,
+ "end_row": 51,
+ "hl_eol": true,
+ "hl_group": "OpencodeDiffAdd",
+ "ns_id": 3,
+ "priority": 5000,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "+",
+ "OpencodeDiffAdd"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "overlay",
+ "virt_text_repeat_linebreak": false
+ }
+ ],
+ [
+ 30,
+ 50,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 31,
+ 51,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 32,
+ 52,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 33,
+ 53,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 34,
+ 54,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 35,
+ 59,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-5-mini",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-20 15:20:17)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_a0234f9c6001JCKYaca1HHwwx6]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 36,
+ 69,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 1000,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "+1",
+ "OpencodeDiffAddText"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": 12
+ }
+ ],
+ [
+ 37,
+ 69,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 1000,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "-1",
+ "OpencodeDiffDeleteText"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": 15
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "add another word",
+ "",
+ "[`test.txt`](test.txt)",
+ "",
+ "----",
+ "",
+ "",
+ "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line now.",
+ "",
+ "** edit** `/home/francis/Projects/_nvim/opencode.nvim/test.txt`",
+ "",
+ "`````txt",
+ " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more",
+ " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again",
+ " ",
+ " ",
+ "",
+ "`````",
+ "",
+ "** Created Snapshot** `1b6ba655`",
+ "",
+ "----",
+ "",
+ "",
+ "**Done:** added the word `again` to `test.txt`.",
+ "",
+ "----",
+ "",
+ "",
+ "add another word",
+ "",
+ "----",
+ "",
+ "",
+ "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the file.",
+ "",
+ "** read** `/home/francis/Projects/_nvim/opencode.nvim/test.txt`",
+ "",
+ "----",
+ "",
+ "",
+ "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that line.",
+ "",
+ "** edit** `/home/francis/Projects/_nvim/opencode.nvim/test.txt`",
+ "",
+ "`````txt",
+ " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again",
+ " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2",
+ " ",
+ " ",
+ "",
+ "`````",
+ "",
+ "** Created Snapshot** `57d83f55`",
+ "",
+ "----",
+ "",
+ "",
+ "**Done:** appended the word `again2` to `test.txt`.",
+ "",
+ "----",
+ "",
+ "> 1 message reverted, 2 tool calls reverted",
+ ">",
+ "> type `/redo` to restore.",
+ "",
+ " test.txt: +1 -1",
+ ""
+ ],
+ "timestamp": 1770748580
+}
\ No newline at end of file
diff --git a/tests/data/redo-once.json b/tests/data/redo-once.json
index a25520de..3abdead1 100644
--- a/tests/data/redo-once.json
+++ b/tests/data/redo-once.json
@@ -1 +1,4265 @@
-[{"properties":{},"type":"server.connected"},{"properties":{"info":{"id":"msg_a0234c0b7001y2o9S1jMaNVZar","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973602999},"role":"user"}},"type":"message.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","text":"add another word\n","id":"prt_a0234c0b8001E8tvDdVNT0NiFh","type":"text","messageID":"msg_a0234c0b7001y2o9S1jMaNVZar"}},"type":"message.part.updated"},{"properties":{"part":{"synthetic":true,"type":"text","text":"Called the Read tool with the following input: {\"filePath\":\"/home/francis/Projects/_nvim/opencode.nvim/test.txt\"}","id":"prt_a0234c0ba001p2wDCCzgtdcf9g","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c0b7001y2o9S1jMaNVZar"}},"type":"message.part.updated"},{"properties":{"part":{"synthetic":true,"type":"text","text":"\n00001| tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more\n00002| \n00003| \n00004| \n","id":"prt_a0234c0ba002ifWGZD21JdnYs6","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c0b7001y2o9S1jMaNVZar"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","type":"file","url":"file:///home/francis/Projects/_nvim/opencode.nvim/test.txt","mime":"text/plain","id":"prt_a0234c0ba003rwMIYGQq901md0","filename":"test.txt","messageID":"msg_a0234c0b7001y2o9S1jMaNVZar"}},"type":"message.part.updated"},{"properties":{"info":{"version":"0.14.6","time":{"created":1760973600383,"updated":1760973603008},"directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"New session - 2025-10-20T15:20:00.383Z"}},"type":"session.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973604758},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234c7960011LTxTvD94hfWCi","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"version":"0.14.6","time":{"created":1760973600383,"updated":1760973605391},"directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Adding word to test.txt"}},"type":"session.updated"},{"properties":{"part":{"type":"step-start","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","id":"prt_a0234d6050012gZEes0qoo3vws","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\")","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`.","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line now","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973608590},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line now.","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_f5xkch2vMvn01ko5Ko4GzNbL","type":"tool","state":{"status":"pending"},"id":"prt_a0234d89c001EJCQkv3qyPNYjc","tool":"edit","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_f5xkch2vMvn01ko5Ko4GzNbL","type":"tool","state":{"input":{"oldString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more","filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt","newString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again"},"time":{"start":1760973609159},"status":"running"},"id":"prt_a0234d89c001EJCQkv3qyPNYjc","tool":"edit","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"file":"/home/francis/Projects/_nvim/opencode.nvim/test.txt"},"type":"file.edited"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_f5xkch2vMvn01ko5Ko4GzNbL","type":"tool","state":{"title":"test.txt","time":{"end":1760973609163,"start":1760973609159},"input":{"oldString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more","filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt","newString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again"},"status":"completed","output":"","metadata":{"diagnostics":{},"diff":"Index: /home/francis/Projects/_nvim/opencode.nvim/test.txt\n===================================================================\n--- /home/francis/Projects/_nvim/opencode.nvim/test.txt\n+++ /home/francis/Projects/_nvim/opencode.nvim/test.txt\n@@ -1,3 +1,3 @@\n-tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again\n \n \n"}},"id":"prt_a0234d89c001EJCQkv3qyPNYjc","tool":"edit","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"end":1760973609181,"start":1760973609181},"text":"I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line now.","id":"prt_a0234d68e0012Ej5Vj7iCasXdB","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"part":{"cost":0,"type":"step-finish","tokens":{"reasoning":0,"input":12788,"output":514,"cache":{"write":0,"read":7168}},"id":"prt_a0234d8df001tlclk7glXfU1WC","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973604758},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12788,"output":514,"cache":{"write":0,"read":7168}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234c7960011LTxTvD94hfWCi","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"hash":"1b6ba655c6c0d899965adff278ac6320d5fc3b12","type":"patch","files":["/home/francis/Projects/_nvim/opencode.nvim/test.txt"],"id":"prt_a0234d8f0001GsHhf2mPuESk1p","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234c7960011LTxTvD94hfWCi"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973604758,"completed":1760973609201},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12788,"output":514,"cache":{"write":0,"read":7168}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234c7960011LTxTvD94hfWCi","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973604758,"completed":1760973609207},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12788,"output":514,"cache":{"write":0,"read":7168}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234c7960011LTxTvD94hfWCi","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973604758,"completed":1760973609207},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12788,"output":514,"cache":{"write":0,"read":7168}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234c7960011LTxTvD94hfWCi","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973609211},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234d8fb001SXyngLjuKSuxOY","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"type":"step-start","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","id":"prt_a0234dbf00016c9aOHUxpQxM0U","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:**","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word `","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word `again","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word `again`","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word `again` to","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word `again` to `","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word `again` to `test","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word `again` to `test.txt","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973609984},"text":"**Done:** added the word `again` to `test.txt`.","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"end":1760973609987,"start":1760973609987},"text":"**Done:** added the word `again` to `test.txt`.","id":"prt_a0234dc00001POFUUsQ0Iz9nze","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"part":{"cost":0,"type":"step-finish","tokens":{"reasoning":0,"input":12921,"output":18,"cache":{"write":0,"read":12672}},"id":"prt_a0234dc03001iO2ubPxctfhnkY","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234d8fb001SXyngLjuKSuxOY"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973609211},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12921,"output":18,"cache":{"write":0,"read":12672}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234d8fb001SXyngLjuKSuxOY","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973609211,"completed":1760973610000},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12921,"output":18,"cache":{"write":0,"read":12672}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234d8fb001SXyngLjuKSuxOY","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973609211,"completed":1760973610001},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12921,"output":18,"cache":{"write":0,"read":12672}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234d8fb001SXyngLjuKSuxOY","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973609211,"completed":1760973610002},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12921,"output":18,"cache":{"write":0,"read":12672}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234d8fb001SXyngLjuKSuxOY","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0"},"type":"session.idle"},{"properties":{"info":{"id":"msg_a0234e308001SKl5bQUibp5gtI","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973611784},"role":"user"}},"type":"message.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","text":"add another word\n","id":"prt_a0234e308002nvLNQpQkMykslq","type":"text","messageID":"msg_a0234e308001SKl5bQUibp5gtI"}},"type":"message.part.updated"},{"properties":{"info":{"version":"0.14.6","time":{"created":1760973600383,"updated":1760973611785},"directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Adding word to test.txt"}},"type":"session.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973611807},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234e31f001m4EsQdPmY3PTtS","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"type":"step-start","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","id":"prt_a0234f2d9001o5Ev43oSWT3Wum","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt`","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content,","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\")","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line.","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceed","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the file","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973615849},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the file.","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_YtG0tPTwncFNNWTaUP6XeTAe","type":"tool","state":{"status":"pending"},"id":"prt_a0234f463001u4vZX0ePvjr6ew","tool":"read","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_YtG0tPTwncFNNWTaUP6XeTAe","type":"tool","state":{"input":{"filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt"},"time":{"start":1760973616230},"status":"running"},"id":"prt_a0234f463001u4vZX0ePvjr6ew","tool":"read","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"end":1760973616230,"start":1760973616230},"text":"I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the file.","id":"prt_a0234f2e9001BHoR88k45jGihp","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_YtG0tPTwncFNNWTaUP6XeTAe","type":"tool","state":{"title":"test.txt","time":{"end":1760973616232,"start":1760973616230},"input":{"filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt"},"status":"completed","output":"\n00001| tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again\n00002| \n00003| \n00004| \n","metadata":{"preview":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again\n\n\n"}},"id":"prt_a0234f463001u4vZX0ePvjr6ew","tool":"read","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"part":{"cost":0,"type":"step-finish","tokens":{"reasoning":0,"input":12949,"output":397,"cache":{"write":0,"read":12928}},"id":"prt_a0234f46800103Qi9hqHZXugdX","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234e31f001m4EsQdPmY3PTtS"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973611807},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12949,"output":397,"cache":{"write":0,"read":12928}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234e31f001m4EsQdPmY3PTtS","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973611807,"completed":1760973616243},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12949,"output":397,"cache":{"write":0,"read":12928}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234e31f001m4EsQdPmY3PTtS","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973611807,"completed":1760973616244},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12949,"output":397,"cache":{"write":0,"read":12928}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234e31f001m4EsQdPmY3PTtS","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973611807,"completed":1760973616245},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":12949,"output":397,"cache":{"write":0,"read":12928}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234e31f001m4EsQdPmY3PTtS","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973616258},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f482001PQbMjWc6W8s0eF","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"type":"step-start","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","id":"prt_a0234f6b0001H9XgBLZ3OdBg68","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\"","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line.","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that line","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973616826},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that line.","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_a9ViHr6etx0cl2DhlyvpIsUV","type":"tool","state":{"status":"pending"},"id":"prt_a0234f9910015mW83bkeVt82ej","tool":"edit","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_a9ViHr6etx0cl2DhlyvpIsUV","type":"tool","state":{"input":{"oldString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again","filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt","newString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2"},"time":{"start":1760973617573},"status":"running"},"id":"prt_a0234f9910015mW83bkeVt82ej","tool":"edit","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"end":1760973617574,"start":1760973617574},"text":"Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that line.","id":"prt_a0234f6ba001Rv1d0qkRn4me9r","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"file":"/home/francis/Projects/_nvim/opencode.nvim/test.txt"},"type":"file.edited"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_a9ViHr6etx0cl2DhlyvpIsUV","type":"tool","state":{"title":"test.txt","time":{"end":1760973617583,"start":1760973617573},"input":{"oldString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again","filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt","newString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2"},"status":"completed","output":"","metadata":{"diagnostics":{},"diff":"Index: /home/francis/Projects/_nvim/opencode.nvim/test.txt\n===================================================================\n--- /home/francis/Projects/_nvim/opencode.nvim/test.txt\n+++ /home/francis/Projects/_nvim/opencode.nvim/test.txt\n@@ -1,3 +1,3 @@\n-tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2\n \n \n"}},"id":"prt_a0234f9910015mW83bkeVt82ej","tool":"edit","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"part":{"cost":0,"type":"step-finish","tokens":{"reasoning":0,"input":13077,"output":126,"cache":{"write":0,"read":12928}},"id":"prt_a0234f9af001iSzXfWH7K1FewT","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973616258},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13077,"output":126,"cache":{"write":0,"read":12928}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f482001PQbMjWc6W8s0eF","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"hash":"57d83f5596cb1f142fbc681d3d93b7184f7f73cd","type":"patch","files":["/home/francis/Projects/_nvim/opencode.nvim/test.txt"],"id":"prt_a0234f9be001oL1wchagZbSt88","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f482001PQbMjWc6W8s0eF"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973616258,"completed":1760973617598},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13077,"output":126,"cache":{"write":0,"read":12928}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f482001PQbMjWc6W8s0eF","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973616258,"completed":1760973617600},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13077,"output":126,"cache":{"write":0,"read":12928}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f482001PQbMjWc6W8s0eF","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973616258,"completed":1760973617600},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13077,"output":126,"cache":{"write":0,"read":12928}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f482001PQbMjWc6W8s0eF","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973617606},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f9c6001JCKYaca1HHwwx6","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"type":"step-start","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","id":"prt_a0234fbf1001oojqKIBCLMQ1mp","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:**","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `again","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `again2","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `again2`","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `again2` to","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `again2` to `","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `again2` to `test","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `again2` to `test.txt","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973618173},"text":"**Done:** appended the word `again2` to `test.txt`.","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"end":1760973618176,"start":1760973618176},"text":"**Done:** appended the word `again2` to `test.txt`.","id":"prt_a0234fbfd001jo8HB4W6xLXRf1","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"part":{"cost":0,"type":"step-finish","tokens":{"reasoning":0,"input":13212,"output":19,"cache":{"write":0,"read":13184}},"id":"prt_a0234fc00001RTCVWXgNk2myYy","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0234f9c6001JCKYaca1HHwwx6"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973617606},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13212,"output":19,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f9c6001JCKYaca1HHwwx6","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973617606,"completed":1760973618194},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13212,"output":19,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f9c6001JCKYaca1HHwwx6","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973617606,"completed":1760973618199},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13212,"output":19,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f9c6001JCKYaca1HHwwx6","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973617606,"completed":1760973618199},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13212,"output":19,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0234f9c6001JCKYaca1HHwwx6","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0"},"type":"session.idle"},{"properties":{"info":{"id":"msg_a0236fd1c001TlwqL8fwvq529i","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973749532},"role":"user"}},"type":"message.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","text":"add another word\n","id":"prt_a0236fd1c002PcRJ8hOgqR7nte","type":"text","messageID":"msg_a0236fd1c001TlwqL8fwvq529i"}},"type":"message.part.updated"},{"properties":{"info":{"version":"0.14.6","time":{"created":1760973600383,"updated":1760973749535},"directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Adding word to test.txt"}},"type":"session.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973749591},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0236fd57001pTnTjSBdFlleCb","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"type":"step-start","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","id":"prt_a0237107b00170PEAkqhAQVD8H","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt`","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content,","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`.","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceed","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the file","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973754529},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the file.","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_4Bb3eCZ89z8Ug2FSjAxY6Xr8","type":"tool","state":{"status":"pending"},"id":"prt_a023712170010ZAVXgtaS80r0m","tool":"read","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_4Bb3eCZ89z8Ug2FSjAxY6Xr8","type":"tool","state":{"input":{"filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt"},"time":{"start":1760973754916},"status":"running"},"id":"prt_a023712170010ZAVXgtaS80r0m","tool":"read","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"end":1760973754916,"start":1760973754916},"text":"I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the file.","id":"prt_a023710a1001dBBJ15P9Tda4Lz","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_4Bb3eCZ89z8Ug2FSjAxY6Xr8","type":"tool","state":{"title":"test.txt","time":{"end":1760973754918,"start":1760973754916},"input":{"filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt"},"status":"completed","output":"\n00001| tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2\n00002| \n00003| \n00004| \n","metadata":{"preview":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2\n\n\n"}},"id":"prt_a023712170010ZAVXgtaS80r0m","tool":"read","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"part":{"cost":0,"type":"step-finish","tokens":{"reasoning":0,"input":13241,"output":457,"cache":{"write":0,"read":13184}},"id":"prt_a02371226001LxXIRETdzHQDxW","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a0236fd57001pTnTjSBdFlleCb"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973749591},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13241,"output":457,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0236fd57001pTnTjSBdFlleCb","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973749591,"completed":1760973754931},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13241,"output":457,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0236fd57001pTnTjSBdFlleCb","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973749591,"completed":1760973754933},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13241,"output":457,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0236fd57001pTnTjSBdFlleCb","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973749591,"completed":1760973754934},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13241,"output":457,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a0236fd57001pTnTjSBdFlleCb","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973754945},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a02371241001PBQAsr8Oc9hqNI","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"type":"step-start","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","id":"prt_a02371fcf001QAGd8I3AJYcZQW","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\"","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt`","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit.","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change now","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973758427},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change now.","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_2GJo632y9iJGpf7eE5seXx0j","type":"tool","state":{"status":"pending"},"id":"prt_a02372387001SiuePn07aa1VNC","tool":"edit","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_2GJo632y9iJGpf7eE5seXx0j","type":"tool","state":{"input":{"oldString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2","filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt","newString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3"},"time":{"start":1760973759397},"status":"running"},"id":"prt_a02372387001SiuePn07aa1VNC","tool":"edit","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"end":1760973759398,"start":1760973759398},"text":"I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change now.","id":"prt_a02371fdb0014iXFfjbCQBgOam","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"file":"/home/francis/Projects/_nvim/opencode.nvim/test.txt"},"type":"file.edited"},{"properties":{"part":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","callID":"call_2GJo632y9iJGpf7eE5seXx0j","type":"tool","state":{"title":"test.txt","time":{"end":1760973759413,"start":1760973759397},"input":{"oldString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2","filePath":"/home/francis/Projects/_nvim/opencode.nvim/test.txt","newString":" tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3"},"status":"completed","output":"","metadata":{"diagnostics":{},"diff":"Index: /home/francis/Projects/_nvim/opencode.nvim/test.txt\n===================================================================\n--- /home/francis/Projects/_nvim/opencode.nvim/test.txt\n+++ /home/francis/Projects/_nvim/opencode.nvim/test.txt\n@@ -1,3 +1,3 @@\n-tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3\n \n \n"}},"id":"prt_a02372387001SiuePn07aa1VNC","tool":"edit","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"part":{"cost":0,"type":"step-finish","tokens":{"reasoning":0,"input":13367,"output":459,"cache":{"write":0,"read":13184}},"id":"prt_a023723b6001LJ3f2pxz1bIYRy","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973754945},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13367,"output":459,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a02371241001PBQAsr8Oc9hqNI","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"hash":"d988cc85565b99017d40ad8baea20225165be9d5","type":"patch","files":["/home/francis/Projects/_nvim/opencode.nvim/test.txt"],"id":"prt_a023723c4001SR03K7sDnOvQ21","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a02371241001PBQAsr8Oc9hqNI"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973754945,"completed":1760973759429},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13367,"output":459,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a02371241001PBQAsr8Oc9hqNI","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973754945,"completed":1760973759430},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13367,"output":459,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a02371241001PBQAsr8Oc9hqNI","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973754945,"completed":1760973759431},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13367,"output":459,"cache":{"write":0,"read":13184}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a02371241001PBQAsr8Oc9hqNI","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973759440},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":0,"output":0,"cache":{"write":0,"read":0}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a023723d0001r87MaJThFssUw1","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"part":{"type":"step-start","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","id":"prt_a02372664001tXq2uEhOCcXuDe","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:**","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `again","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `again3","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `again3`","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `again3` to","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `again3` to `","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `again3` to `test","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `again3` to `test.txt","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"start":1760973760122},"text":"**Done:** appended the word `again3` to `test.txt`.","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"type":"text","time":{"end":1760973760125,"start":1760973760125},"text":"**Done:** appended the word `again3` to `test.txt`.","id":"prt_a0237267a001dvydCUWE7FBrLn","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"part":{"cost":0,"type":"step-finish","tokens":{"reasoning":0,"input":13509,"output":19,"cache":{"write":0,"read":13312}},"id":"prt_a0237267e001nad2YARrEmo6hb","sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","messageID":"msg_a023723d0001r87MaJThFssUw1"}},"type":"message.part.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973759440},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13509,"output":19,"cache":{"write":0,"read":13312}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a023723d0001r87MaJThFssUw1","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973759440,"completed":1760973760142},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13509,"output":19,"cache":{"write":0,"read":13312}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a023723d0001r87MaJThFssUw1","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973759440,"completed":1760973760147},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13509,"output":19,"cache":{"write":0,"read":13312}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a023723d0001r87MaJThFssUw1","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"info":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","time":{"created":1760973759440,"completed":1760973760148},"mode":"build","path":{"cwd":"/home/francis/Projects/_nvim/opencode.nvim","root":"/home/francis/Projects/_nvim/opencode.nvim"},"tokens":{"reasoning":0,"input":13509,"output":19,"cache":{"write":0,"read":13312}},"cost":0,"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"providerID":"github-copilot","id":"msg_a023723d0001r87MaJThFssUw1","modelID":"gpt-5-mini","role":"assistant"}},"type":"message.updated"},{"properties":{"sessionID":"ses_5fdcb4981ffe4xsF2IbnPjSWu0"},"type":"session.idle"},{"properties":{"info":{"version":"0.14.6","time":{"created":1760973600383,"updated":1760978265898},"directory":"/home/francis/Projects/_nvim/opencode.nvim","revert":{"diff":"diff --git a/test.txt b/test.txt\nindex 7191e44..f2caa07 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,3 +1,3 @@\n- tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2","snapshot":"281b11ee830296ddff05bf14d0d7b9ef4b1ac8af","messageID":"msg_a0236fd1c001TlwqL8fwvq529i"},"id":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Adding word to test.txt"}},"type":"session.updated"},{"properties":{"info":{"version":"0.14.6","time":{"created":1760973600383,"updated":1760978268997},"directory":"/home/francis/Projects/_nvim/opencode.nvim","revert":{"diff":"diff --git a/test.txt b/test.txt\nindex 7191e44..387f18d 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,3 +1,3 @@\n- tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again","snapshot":"281b11ee830296ddff05bf14d0d7b9ef4b1ac8af","messageID":"msg_a0234e308001SKl5bQUibp5gtI"},"id":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Adding word to test.txt"}},"type":"session.updated"},{"properties":{"info":{"version":"0.14.6","time":{"created":1760973600383,"updated":1760978282075},"directory":"/home/francis/Projects/_nvim/opencode.nvim","revert":{"diff":"diff --git a/test.txt b/test.txt\nindex 7191e44..f2caa07 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,3 +1,3 @@\n- tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2","snapshot":"281b11ee830296ddff05bf14d0d7b9ef4b1ac8af","messageID":"msg_a0236fd1c001TlwqL8fwvq529i"},"id":"ses_5fdcb4981ffe4xsF2IbnPjSWu0","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Adding word to test.txt"}},"type":"session.updated"}]
+[
+ { "properties": {}, "type": "server.connected" },
+ {
+ "properties": {
+ "info": {
+ "id": "msg_a0234c0b7001y2o9S1jMaNVZar",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973602999 },
+ "role": "user"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "text": "add another word\n",
+ "id": "prt_a0234c0b8001E8tvDdVNT0NiFh",
+ "type": "text",
+ "messageID": "msg_a0234c0b7001y2o9S1jMaNVZar"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "synthetic": true,
+ "type": "text",
+ "text": "Called the Read tool with the following input: {\"filePath\":\"/home/francis/Projects/_nvim/opencode.nvim/test.txt\"}",
+ "id": "prt_a0234c0ba001p2wDCCzgtdcf9g",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c0b7001y2o9S1jMaNVZar"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "synthetic": true,
+ "type": "text",
+ "text": "\n00001| tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more\n00002| \n00003| \n00004| \n",
+ "id": "prt_a0234c0ba002ifWGZD21JdnYs6",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c0b7001y2o9S1jMaNVZar"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "type": "file",
+ "url": "file:///home/francis/Projects/_nvim/opencode.nvim/test.txt",
+ "mime": "text/plain",
+ "id": "prt_a0234c0ba003rwMIYGQq901md0",
+ "filename": "test.txt",
+ "messageID": "msg_a0234c0b7001y2o9S1jMaNVZar"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "version": "0.14.6",
+ "time": { "created": 1760973600383, "updated": 1760973603008 },
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "title": "New session - 2025-10-20T15:20:00.383Z"
+ }
+ },
+ "type": "session.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973604758 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234c7960011LTxTvD94hfWCi",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "version": "0.14.6",
+ "time": { "created": 1760973600383, "updated": 1760973605391 },
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "title": "Adding word to test.txt"
+ }
+ },
+ "type": "session.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "id": "prt_a0234d6050012gZEes0qoo3vws",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\")",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`.",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line now",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973608590 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line now.",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_f5xkch2vMvn01ko5Ko4GzNbL",
+ "type": "tool",
+ "state": { "status": "pending" },
+ "id": "prt_a0234d89c001EJCQkv3qyPNYjc",
+ "tool": "edit",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_f5xkch2vMvn01ko5Ko4GzNbL",
+ "type": "tool",
+ "state": {
+ "input": {
+ "oldString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more",
+ "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt",
+ "newString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again"
+ },
+ "time": { "start": 1760973609159 },
+ "status": "running"
+ },
+ "id": "prt_a0234d89c001EJCQkv3qyPNYjc",
+ "tool": "edit",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": { "file": "/home/francis/Projects/_nvim/opencode.nvim/test.txt" }, "type": "file.edited" },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_f5xkch2vMvn01ko5Ko4GzNbL",
+ "type": "tool",
+ "state": {
+ "title": "test.txt",
+ "time": { "end": 1760973609163, "start": 1760973609159 },
+ "input": {
+ "oldString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more",
+ "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt",
+ "newString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again"
+ },
+ "status": "completed",
+ "output": "",
+ "metadata": {
+ "diagnostics": {},
+ "diff": "Index: /home/francis/Projects/_nvim/opencode.nvim/test.txt\n===================================================================\n--- /home/francis/Projects/_nvim/opencode.nvim/test.txt\n+++ /home/francis/Projects/_nvim/opencode.nvim/test.txt\n@@ -1,3 +1,3 @@\n-tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again\n \n \n"
+ }
+ },
+ "id": "prt_a0234d89c001EJCQkv3qyPNYjc",
+ "tool": "edit",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "end": 1760973609181, "start": 1760973609181 },
+ "text": "I'll append a single word (\"again\") to the first line of `test.txt`. Applying a precise edit to the existing line now.",
+ "id": "prt_a0234d68e0012Ej5Vj7iCasXdB",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "cost": 0,
+ "type": "step-finish",
+ "tokens": { "reasoning": 0, "input": 12788, "output": 514, "cache": { "write": 0, "read": 7168 } },
+ "id": "prt_a0234d8df001tlclk7glXfU1WC",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973604758 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12788, "output": 514, "cache": { "write": 0, "read": 7168 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234c7960011LTxTvD94hfWCi",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "hash": "1b6ba655c6c0d899965adff278ac6320d5fc3b12",
+ "type": "patch",
+ "files": ["/home/francis/Projects/_nvim/opencode.nvim/test.txt"],
+ "id": "prt_a0234d8f0001GsHhf2mPuESk1p",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234c7960011LTxTvD94hfWCi"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973604758, "completed": 1760973609201 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12788, "output": 514, "cache": { "write": 0, "read": 7168 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234c7960011LTxTvD94hfWCi",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973604758, "completed": 1760973609207 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12788, "output": 514, "cache": { "write": 0, "read": 7168 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234c7960011LTxTvD94hfWCi",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973604758, "completed": 1760973609207 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12788, "output": 514, "cache": { "write": 0, "read": 7168 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234c7960011LTxTvD94hfWCi",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973609211 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234d8fb001SXyngLjuKSuxOY",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "id": "prt_a0234dbf00016c9aOHUxpQxM0U",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:**",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word `",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word `again",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word `again`",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word `again` to",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word `again` to `",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word `again` to `test",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word `again` to `test.txt",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973609984 },
+ "text": "**Done:** added the word `again` to `test.txt`.",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "end": 1760973609987, "start": 1760973609987 },
+ "text": "**Done:** added the word `again` to `test.txt`.",
+ "id": "prt_a0234dc00001POFUUsQ0Iz9nze",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "cost": 0,
+ "type": "step-finish",
+ "tokens": { "reasoning": 0, "input": 12921, "output": 18, "cache": { "write": 0, "read": 12672 } },
+ "id": "prt_a0234dc03001iO2ubPxctfhnkY",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234d8fb001SXyngLjuKSuxOY"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973609211 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12921, "output": 18, "cache": { "write": 0, "read": 12672 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234d8fb001SXyngLjuKSuxOY",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973609211, "completed": 1760973610000 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12921, "output": 18, "cache": { "write": 0, "read": 12672 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234d8fb001SXyngLjuKSuxOY",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973609211, "completed": 1760973610001 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12921, "output": 18, "cache": { "write": 0, "read": 12672 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234d8fb001SXyngLjuKSuxOY",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973609211, "completed": 1760973610002 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12921, "output": 18, "cache": { "write": 0, "read": 12672 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234d8fb001SXyngLjuKSuxOY",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ { "properties": { "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0" }, "type": "session.idle" },
+ {
+ "properties": {
+ "info": {
+ "id": "msg_a0234e308001SKl5bQUibp5gtI",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973611784 },
+ "role": "user"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "text": "add another word\n",
+ "id": "prt_a0234e308002nvLNQpQkMykslq",
+ "type": "text",
+ "messageID": "msg_a0234e308001SKl5bQUibp5gtI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "version": "0.14.6",
+ "time": { "created": 1760973600383, "updated": 1760973611785 },
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "title": "Adding word to test.txt"
+ }
+ },
+ "type": "session.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973611807 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234e31f001m4EsQdPmY3PTtS",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "id": "prt_a0234f2d9001o5Ev43oSWT3Wum",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt`",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content,",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\")",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line.",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceed",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the file",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973615849 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the file.",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_YtG0tPTwncFNNWTaUP6XeTAe",
+ "type": "tool",
+ "state": { "status": "pending" },
+ "id": "prt_a0234f463001u4vZX0ePvjr6ew",
+ "tool": "read",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_YtG0tPTwncFNNWTaUP6XeTAe",
+ "type": "tool",
+ "state": {
+ "input": { "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt" },
+ "time": { "start": 1760973616230 },
+ "status": "running"
+ },
+ "id": "prt_a0234f463001u4vZX0ePvjr6ew",
+ "tool": "read",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "end": 1760973616230, "start": 1760973616230 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append one word (\"again2\") to that line. Proceeding to read the file.",
+ "id": "prt_a0234f2e9001BHoR88k45jGihp",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_YtG0tPTwncFNNWTaUP6XeTAe",
+ "type": "tool",
+ "state": {
+ "title": "test.txt",
+ "time": { "end": 1760973616232, "start": 1760973616230 },
+ "input": { "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt" },
+ "status": "completed",
+ "output": "\n00001| tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again\n00002| \n00003| \n00004| \n",
+ "metadata": {
+ "preview": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again\n\n\n"
+ }
+ },
+ "id": "prt_a0234f463001u4vZX0ePvjr6ew",
+ "tool": "read",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "cost": 0,
+ "type": "step-finish",
+ "tokens": { "reasoning": 0, "input": 12949, "output": 397, "cache": { "write": 0, "read": 12928 } },
+ "id": "prt_a0234f46800103Qi9hqHZXugdX",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234e31f001m4EsQdPmY3PTtS"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973611807 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12949, "output": 397, "cache": { "write": 0, "read": 12928 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234e31f001m4EsQdPmY3PTtS",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973611807, "completed": 1760973616243 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12949, "output": 397, "cache": { "write": 0, "read": 12928 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234e31f001m4EsQdPmY3PTtS",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973611807, "completed": 1760973616244 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12949, "output": 397, "cache": { "write": 0, "read": 12928 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234e31f001m4EsQdPmY3PTtS",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973611807, "completed": 1760973616245 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 12949, "output": 397, "cache": { "write": 0, "read": 12928 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234e31f001m4EsQdPmY3PTtS",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973616258 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f482001PQbMjWc6W8s0eF",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "id": "prt_a0234f6b0001H9XgBLZ3OdBg68",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\"",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line.",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that line",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973616826 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that line.",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_a9ViHr6etx0cl2DhlyvpIsUV",
+ "type": "tool",
+ "state": { "status": "pending" },
+ "id": "prt_a0234f9910015mW83bkeVt82ej",
+ "tool": "edit",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_a9ViHr6etx0cl2DhlyvpIsUV",
+ "type": "tool",
+ "state": {
+ "input": {
+ "oldString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again",
+ "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt",
+ "newString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2"
+ },
+ "time": { "start": 1760973617573 },
+ "status": "running"
+ },
+ "id": "prt_a0234f9910015mW83bkeVt82ej",
+ "tool": "edit",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "end": 1760973617574, "start": 1760973617574 },
+ "text": "Now I'll append the word \"again2\" to the first line. I'll apply an exact in-place edit to update that line.",
+ "id": "prt_a0234f6ba001Rv1d0qkRn4me9r",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": { "file": "/home/francis/Projects/_nvim/opencode.nvim/test.txt" }, "type": "file.edited" },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_a9ViHr6etx0cl2DhlyvpIsUV",
+ "type": "tool",
+ "state": {
+ "title": "test.txt",
+ "time": { "end": 1760973617583, "start": 1760973617573 },
+ "input": {
+ "oldString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again",
+ "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt",
+ "newString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2"
+ },
+ "status": "completed",
+ "output": "",
+ "metadata": {
+ "diagnostics": {},
+ "diff": "Index: /home/francis/Projects/_nvim/opencode.nvim/test.txt\n===================================================================\n--- /home/francis/Projects/_nvim/opencode.nvim/test.txt\n+++ /home/francis/Projects/_nvim/opencode.nvim/test.txt\n@@ -1,3 +1,3 @@\n-tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2\n \n \n"
+ }
+ },
+ "id": "prt_a0234f9910015mW83bkeVt82ej",
+ "tool": "edit",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "cost": 0,
+ "type": "step-finish",
+ "tokens": { "reasoning": 0, "input": 13077, "output": 126, "cache": { "write": 0, "read": 12928 } },
+ "id": "prt_a0234f9af001iSzXfWH7K1FewT",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973616258 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13077, "output": 126, "cache": { "write": 0, "read": 12928 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f482001PQbMjWc6W8s0eF",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "hash": "57d83f5596cb1f142fbc681d3d93b7184f7f73cd",
+ "type": "patch",
+ "files": ["/home/francis/Projects/_nvim/opencode.nvim/test.txt"],
+ "id": "prt_a0234f9be001oL1wchagZbSt88",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f482001PQbMjWc6W8s0eF"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973616258, "completed": 1760973617598 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13077, "output": 126, "cache": { "write": 0, "read": 12928 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f482001PQbMjWc6W8s0eF",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973616258, "completed": 1760973617600 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13077, "output": 126, "cache": { "write": 0, "read": 12928 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f482001PQbMjWc6W8s0eF",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973616258, "completed": 1760973617600 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13077, "output": 126, "cache": { "write": 0, "read": 12928 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f482001PQbMjWc6W8s0eF",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973617606 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f9c6001JCKYaca1HHwwx6",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "id": "prt_a0234fbf1001oojqKIBCLMQ1mp",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:**",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `again",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `again2",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `again2`",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `again2` to",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `again2` to `",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `again2` to `test",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `again2` to `test.txt",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973618173 },
+ "text": "**Done:** appended the word `again2` to `test.txt`.",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "end": 1760973618176, "start": 1760973618176 },
+ "text": "**Done:** appended the word `again2` to `test.txt`.",
+ "id": "prt_a0234fbfd001jo8HB4W6xLXRf1",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "cost": 0,
+ "type": "step-finish",
+ "tokens": { "reasoning": 0, "input": 13212, "output": 19, "cache": { "write": 0, "read": 13184 } },
+ "id": "prt_a0234fc00001RTCVWXgNk2myYy",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0234f9c6001JCKYaca1HHwwx6"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973617606 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13212, "output": 19, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f9c6001JCKYaca1HHwwx6",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973617606, "completed": 1760973618194 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13212, "output": 19, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f9c6001JCKYaca1HHwwx6",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973617606, "completed": 1760973618199 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13212, "output": 19, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f9c6001JCKYaca1HHwwx6",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973617606, "completed": 1760973618199 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13212, "output": 19, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0234f9c6001JCKYaca1HHwwx6",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ { "properties": { "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0" }, "type": "session.idle" },
+ {
+ "properties": {
+ "info": {
+ "id": "msg_a0236fd1c001TlwqL8fwvq529i",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973749532 },
+ "role": "user"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "text": "add another word\n",
+ "id": "prt_a0236fd1c002PcRJ8hOgqR7nte",
+ "type": "text",
+ "messageID": "msg_a0236fd1c001TlwqL8fwvq529i"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "version": "0.14.6",
+ "time": { "created": 1760973600383, "updated": 1760973749535 },
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "id": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "title": "Adding word to test.txt"
+ }
+ },
+ "type": "session.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973749591 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0236fd57001pTnTjSBdFlleCb",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "id": "prt_a0237107b00170PEAkqhAQVD8H",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt`",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content,",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`.",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceed",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the file",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973754529 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the file.",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_4Bb3eCZ89z8Ug2FSjAxY6Xr8",
+ "type": "tool",
+ "state": { "status": "pending" },
+ "id": "prt_a023712170010ZAVXgtaS80r0m",
+ "tool": "read",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_4Bb3eCZ89z8Ug2FSjAxY6Xr8",
+ "type": "tool",
+ "state": {
+ "input": { "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt" },
+ "time": { "start": 1760973754916 },
+ "status": "running"
+ },
+ "id": "prt_a023712170010ZAVXgtaS80r0m",
+ "tool": "read",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "end": 1760973754916, "start": 1760973754916 },
+ "text": "I'll read `test.txt` to get the current first-line content, then append the word `again3`. Proceeding to read the file.",
+ "id": "prt_a023710a1001dBBJ15P9Tda4Lz",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_4Bb3eCZ89z8Ug2FSjAxY6Xr8",
+ "type": "tool",
+ "state": {
+ "title": "test.txt",
+ "time": { "end": 1760973754918, "start": 1760973754916 },
+ "input": { "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt" },
+ "status": "completed",
+ "output": "\n00001| tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2\n00002| \n00003| \n00004| \n",
+ "metadata": {
+ "preview": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2\n\n\n"
+ }
+ },
+ "id": "prt_a023712170010ZAVXgtaS80r0m",
+ "tool": "read",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "cost": 0,
+ "type": "step-finish",
+ "tokens": { "reasoning": 0, "input": 13241, "output": 457, "cache": { "write": 0, "read": 13184 } },
+ "id": "prt_a02371226001LxXIRETdzHQDxW",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a0236fd57001pTnTjSBdFlleCb"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973749591 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13241, "output": 457, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0236fd57001pTnTjSBdFlleCb",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973749591, "completed": 1760973754931 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13241, "output": 457, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0236fd57001pTnTjSBdFlleCb",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973749591, "completed": 1760973754933 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13241, "output": 457, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0236fd57001pTnTjSBdFlleCb",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973749591, "completed": 1760973754934 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13241, "output": 457, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a0236fd57001pTnTjSBdFlleCb",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973754945 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a02371241001PBQAsr8Oc9hqNI",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "id": "prt_a02371fcf001QAGd8I3AJYcZQW",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\"",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt`",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit.",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change now",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973758427 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change now.",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_2GJo632y9iJGpf7eE5seXx0j",
+ "type": "tool",
+ "state": { "status": "pending" },
+ "id": "prt_a02372387001SiuePn07aa1VNC",
+ "tool": "edit",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_2GJo632y9iJGpf7eE5seXx0j",
+ "type": "tool",
+ "state": {
+ "input": {
+ "oldString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2",
+ "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt",
+ "newString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3"
+ },
+ "time": { "start": 1760973759397 },
+ "status": "running"
+ },
+ "id": "prt_a02372387001SiuePn07aa1VNC",
+ "tool": "edit",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "end": 1760973759398, "start": 1760973759398 },
+ "text": "I'll append the word \"again3\" to the first line of `test.txt` with an exact in-place edit. Applying the change now.",
+ "id": "prt_a02371fdb0014iXFfjbCQBgOam",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ { "properties": { "file": "/home/francis/Projects/_nvim/opencode.nvim/test.txt" }, "type": "file.edited" },
+ {
+ "properties": {
+ "part": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "callID": "call_2GJo632y9iJGpf7eE5seXx0j",
+ "type": "tool",
+ "state": {
+ "title": "test.txt",
+ "time": { "end": 1760973759413, "start": 1760973759397 },
+ "input": {
+ "oldString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2",
+ "filePath": "/home/francis/Projects/_nvim/opencode.nvim/test.txt",
+ "newString": " tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3"
+ },
+ "status": "completed",
+ "output": "",
+ "metadata": {
+ "diagnostics": {},
+ "diff": "Index: /home/francis/Projects/_nvim/opencode.nvim/test.txt\n===================================================================\n--- /home/francis/Projects/_nvim/opencode.nvim/test.txt\n+++ /home/francis/Projects/_nvim/opencode.nvim/test.txt\n@@ -1,3 +1,3 @@\n-tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3\n \n \n"
+ }
+ },
+ "id": "prt_a02372387001SiuePn07aa1VNC",
+ "tool": "edit",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "cost": 0,
+ "type": "step-finish",
+ "tokens": { "reasoning": 0, "input": 13367, "output": 459, "cache": { "write": 0, "read": 13184 } },
+ "id": "prt_a023723b6001LJ3f2pxz1bIYRy",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973754945 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13367, "output": 459, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a02371241001PBQAsr8Oc9hqNI",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "hash": "d988cc85565b99017d40ad8baea20225165be9d5",
+ "type": "patch",
+ "files": ["/home/francis/Projects/_nvim/opencode.nvim/test.txt"],
+ "id": "prt_a023723c4001SR03K7sDnOvQ21",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a02371241001PBQAsr8Oc9hqNI"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973754945, "completed": 1760973759429 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13367, "output": 459, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a02371241001PBQAsr8Oc9hqNI",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973754945, "completed": 1760973759430 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13367, "output": 459, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a02371241001PBQAsr8Oc9hqNI",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973754945, "completed": 1760973759431 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13367, "output": 459, "cache": { "write": 0, "read": 13184 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a02371241001PBQAsr8Oc9hqNI",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973759440 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 0, "output": 0, "cache": { "write": 0, "read": 0 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a023723d0001r87MaJThFssUw1",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "step-start",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "id": "prt_a02372664001tXq2uEhOCcXuDe",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:**",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `again",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `again3",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `again3`",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `again3` to",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `again3` to `",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `again3` to `test",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `again3` to `test.txt",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "start": 1760973760122 },
+ "text": "**Done:** appended the word `again3` to `test.txt`.",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "type": "text",
+ "time": { "end": 1760973760125, "start": 1760973760125 },
+ "text": "**Done:** appended the word `again3` to `test.txt`.",
+ "id": "prt_a0237267a001dvydCUWE7FBrLn",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "part": {
+ "cost": 0,
+ "type": "step-finish",
+ "tokens": { "reasoning": 0, "input": 13509, "output": 19, "cache": { "write": 0, "read": 13312 } },
+ "id": "prt_a0237267e001nad2YARrEmo6hb",
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "messageID": "msg_a023723d0001r87MaJThFssUw1"
+ }
+ },
+ "type": "message.part.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973759440 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13509, "output": 19, "cache": { "write": 0, "read": 13312 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a023723d0001r87MaJThFssUw1",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973759440, "completed": 1760973760142 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13509, "output": 19, "cache": { "write": 0, "read": 13312 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a023723d0001r87MaJThFssUw1",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973759440, "completed": 1760973760147 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13509, "output": 19, "cache": { "write": 0, "read": 13312 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a023723d0001r87MaJThFssUw1",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "time": { "created": 1760973759440, "completed": 1760973760148 },
+ "mode": "build",
+ "path": {
+ "cwd": "/home/francis/Projects/_nvim/opencode.nvim",
+ "root": "/home/francis/Projects/_nvim/opencode.nvim"
+ },
+ "tokens": { "reasoning": 0, "input": 13509, "output": 19, "cache": { "write": 0, "read": 13312 } },
+ "cost": 0,
+ "system": [
+ "You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what you’re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if you’re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences (8–12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with what’s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n\n**Examples:**\n- “I’ve explored the repo; now checking the API route definitions.”\n- “Next, I’ll edit the config and update the related tests.”\n- “I’m about to scaffold the CLI commands and helper functions.”\n- “Ok cool, so I’ve wrapped my head around the repo. Now digging into the API routes.”\n- “Config’s looking tidy. Next up is editing helpers to keep things in sync.”\n- “Finished poking at the DB gateway. I will now chase down error handling.”\n- “Alright, build pipeline order is interesting. Checking how it reports failures.”\n- “Spotted a clever caching util; now hunting where it gets used.”\n\n**Avoiding a preamble for every trivial read (e.g., `cat` a single file) unless it’s part of a larger grouped action.\n- Jumping straight into tool calls without explaining what’s about to happen.\n- Writing overly long or speculative preambles — focus on immediate, tangible next steps.\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and\nrenders them to the user. Using the tool helps demonstrate that you've\nunderstood the task and convey how you're approaching it. Plans can help to make\ncomplex, ambiguous, or multi-phase work clearer and more collaborative for the\nuser. A good plan should break the task into meaningful, logically ordered steps\nthat are easy to verify as you go. Note that plans are not for padding out\nsimple work with filler steps or stating the obvious. Do not repeat the full\ncontents of the plan after a `todowrite` call — the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nUse a plan when:\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\nSkip a plan when:\n- The task is simple and direct.\n- Breaking it down would only produce literal or trivial steps.\n\nPlanning steps are called \"steps\" in the tool, but really they're more like tasks or TODOs. As such they should be very concise descriptions of non-obvious work that an engineer might do like \"Write the API spec\", then \"Update the backend\", then \"Implement the frontend\". On the other hand, it's obvious that you'll usually have to \"Explore the codebase\" or \"Implement the changes\", so those are not worth tracking in your plan.\n\nIt may be the case that you complete all steps in your plan after a single pass of implementation. If this is the case, you can simply mark all the planned steps as completed. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level edits, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"【F:README.md†L5-L14】\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Testing your work\n\nIf the codebase has tests or the ability to build or run, you should use them to verify that your work is complete. Generally, your testing philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests, or where the patterns don't indicate so.\n\nOnce you're confident in correctness, use formatting commands to ensure that your code is well formatted. These commands can take time so you should run them on as precise a target as possible. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n- *read-only*: You can only read files.\n- *workspace-write*: You can read files. You can write to files in your workspace folder, but not outside it.\n- *danger-full-access*: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n- *ON*\n- *OFF*\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n- *untrusted*: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- *on-failure*: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- *on-request*: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- *never*: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user’s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As\nsuch there's no need to show the full contents of large files you have already\nwritten unless the user explicitly asks for them. Similarly, if you've created\nor modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"—just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there’s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n- Use only when they improve clarity — they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n- Use `-` followed by a space for every bullet.\n- Bold the keyword, then colon + concise description.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4–6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether it’s a keyword (`**`) or inline code/path (`` ` ``).\n\n**Structure**\n- Place related bullets together; don’t mix unrelated concepts in the same section.\n- Order sections from general → specific → supporting info.\n- For subsections (e.g., “Binaries” under “Rust Workspace”), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results → use clear headers and grouped bullets.\n - Simple results → minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual — no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., “Runs tests” not “This will run tests”).\n- Keep descriptions self-contained; don’t refer to “above” or “below”.\n- Use parallel structure in lists for consistency.\n\n**Don’t**\n- Don’t use literal words “bold” or “monospace” in the content.\n- Don’t nest bullets or create deep hierarchies.\n- Don’t output ANSI escape codes directly — the CLI renderer applies them.\n- Don’t cram unrelated keywords into a single bullet; split for clarity.\n- Don’t let keyword lists run long — wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n",
+ "Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Oct 20 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 1\" \"+sleep 500m | qa!\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+sleep 500m | qa\"`\n ```\n\n ```\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines ≤ 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"
+ ],
+ "providerID": "github-copilot",
+ "id": "msg_a023723d0001r87MaJThFssUw1",
+ "modelID": "gpt-5-mini",
+ "role": "assistant"
+ }
+ },
+ "type": "message.updated"
+ },
+ { "properties": { "sessionID": "ses_5fdcb4981ffe4xsF2IbnPjSWu0" }, "type": "session.idle" },
+ {
+ "properties": {
+ "info": {
+ "version": "0.14.6",
+ "time": { "created": 1760973600383, "updated": 1760978265898 },
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "revert": {
+ "diff": "diff --git a/test.txt b/test.txt\nindex 7191e44..f2caa07 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,3 +1,3 @@\n- tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2",
+ "snapshot": "281b11ee830296ddff05bf14d0d7b9ef4b1ac8af",
+ "messageID": "msg_a0236fd1c001TlwqL8fwvq529i"
+ },
+ "id": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "title": "Adding word to test.txt"
+ }
+ },
+ "type": "session.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "version": "0.14.6",
+ "time": { "created": 1760973600383, "updated": 1760978268997 },
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "revert": {
+ "diff": "diff --git a/test.txt b/test.txt\nindex 7191e44..387f18d 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,3 +1,3 @@\n- tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again",
+ "snapshot": "281b11ee830296ddff05bf14d0d7b9ef4b1ac8af",
+ "messageID": "msg_a0234e308001SKl5bQUibp5gtI"
+ },
+ "id": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "title": "Adding word to test.txt"
+ }
+ },
+ "type": "session.updated"
+ },
+ {
+ "properties": {
+ "info": {
+ "version": "0.14.6",
+ "time": { "created": 1760973600383, "updated": 1760978282075 },
+ "directory": "/home/francis/Projects/_nvim/opencode.nvim",
+ "revert": {
+ "diff": "diff --git a/test.txt b/test.txt\nindex 7191e44..f2caa07 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,3 +1,3 @@\n- tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2 again3\n+ tangram quiver saffron nebula cobalt murmur plinth zephyr ember lattice cadenza another yet extra more again again2",
+ "snapshot": "281b11ee830296ddff05bf14d0d7b9ef4b1ac8af",
+ "messageID": "msg_a0236fd1c001TlwqL8fwvq529i"
+ },
+ "id": "ses_5fdcb4981ffe4xsF2IbnPjSWu0",
+ "projectID": "29d43526f88157cd4edd071b899dd01f240b771b",
+ "title": "Adding word to test.txt"
+ }
+ },
+ "type": "session.updated"
+ }
+]
diff --git a/tests/data/revert.expected.json b/tests/data/revert.expected.json
index cd1b917f..c5df5321 100644
--- a/tests/data/revert.expected.json
+++ b/tests/data/revert.expected.json
@@ -1 +1,751 @@
-{"lines":["----","","","write 10 random words","","[`poem.md`](poem.md)","","----","","","Here are 10 random words:","","1. Lantern ","2. Whisper ","3. Velvet ","4. Orbit ","5. Timber ","6. Quiver ","7. Mosaic ","8. Ember ","9. Spiral ","10. Glimmer","","Let me know if you need them in a specific format or want to use them in a file!","","----","","","write 10 random words to the file","","----","","","I will write 10 random words to poem.md, each on a new line.","","Proceeding to update the file now.","","** write** `/home/francis/Projects/_nvim/opencode.nvim/poem.md`","","`````markdown","Lantern","Whisper","Velvet","Orbit","Timber","Quiver","Mosaic","Ember","Spiral","Glimmer","","`````","","** Created Snapshot** `c410b2b4`","","----","","","The file poem.md has been updated with 10 random words, each on a new line. Task complete! If you need anything else, let me know.","","----","","> 2 messages reverted, 4 tool calls reverted",">","> type `/redo` to restore.",""," poem.md: -20",""],"actions":[{"text":"[R]evert file","display_line":53,"key":"R","range":{"to":53,"from":53},"args":["c410b2b4024de020aea223c5248eec89216de53f"],"type":"diff_revert_selected_file"},{"text":"Revert [A]ll","display_line":53,"key":"A","range":{"to":53,"from":53},"args":["c410b2b4024de020aea223c5248eec89216de53f"],"type":"diff_revert_all"},{"text":"[D]iff","display_line":53,"key":"D","range":{"to":53,"from":53},"args":["c410b2b4024de020aea223c5248eec89216de53f"],"type":"diff_open"}],"extmarks":[[1,1,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":false,"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-19 17:50:43)","OpencodeHint"],[" [msg_9fd985573001fk1Xlot7uyDgTo]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":10,"right_gravity":true}],[2,2,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[3,3,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[4,4,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[5,5,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[6,8,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2025-10-19 17:50:44)","OpencodeHint"],[" [msg_9fd985a4d001wOX3Op7CpFiCTq]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":10,"right_gravity":true}],[7,26,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":false,"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-19 17:50:57)","OpencodeHint"],[" [msg_9fd988c92001w0IZCVPQsN6xa9]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":10,"right_gravity":true}],[8,27,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[9,28,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[10,31,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2025-10-19 17:50:57)","OpencodeHint"],[" [msg_9fd988ca7001lgaGttpI4YeGSA]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":10,"right_gravity":true}],[11,37,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true}],[12,38,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true}],[13,39,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true}],[14,40,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true}],[15,41,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true}],[16,42,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true}],[17,43,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true}],[18,44,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true}],[19,45,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true}],[20,46,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true}],[21,47,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true}],[22,48,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true}],[23,49,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true}],[24,50,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true}],[25,51,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true}],[26,56,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2025-10-19 17:50:59)","OpencodeHint"],[" [msg_9fd98942d001elqd2sd8CZeOoA]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":10,"right_gravity":true}],[27,66,0,{"ns_id":3,"virt_text_hide":false,"virt_text_repeat_linebreak":false,"virt_text":[["-20","OpencodeDiffDeleteText"]],"virt_text_pos":"win_col","virt_text_win_col":11,"priority":1000,"right_gravity":true}]],"timestamp":1769172286}
+{
+ "actions": [
+ {
+ "args": [
+ "c410b2b4024de020aea223c5248eec89216de53f"
+ ],
+ "display_line": 53,
+ "key": "R",
+ "range": {
+ "from": 53,
+ "to": 53
+ },
+ "text": "[R]evert file",
+ "type": "diff_revert_selected_file"
+ },
+ {
+ "args": [
+ "c410b2b4024de020aea223c5248eec89216de53f"
+ ],
+ "display_line": 53,
+ "key": "A",
+ "range": {
+ "from": 53,
+ "to": 53
+ },
+ "text": "Revert [A]ll",
+ "type": "diff_revert_all"
+ },
+ {
+ "args": [
+ "c410b2b4024de020aea223c5248eec89216de53f"
+ ],
+ "display_line": 53,
+ "key": "D",
+ "range": {
+ "from": 53,
+ "to": 53
+ },
+ "text": "[D]iff",
+ "type": "diff_open"
+ }
+ ],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-19 17:50:43)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9fd985573001fk1Xlot7uyDgTo]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 2,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 3,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 4,
+ 4,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 5,
+ 5,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 6,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-4.1",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-19 17:50:44)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9fd985a4d001wOX3Op7CpFiCTq]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 7,
+ 26,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-19 17:50:57)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9fd988c92001w0IZCVPQsN6xa9]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 8,
+ 27,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 9,
+ 28,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 10,
+ 31,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-4.1",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-19 17:50:57)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9fd988ca7001lgaGttpI4YeGSA]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 11,
+ 37,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 12,
+ 38,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 13,
+ 39,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 14,
+ 40,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 15,
+ 41,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 16,
+ 42,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 17,
+ 43,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 18,
+ 44,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 19,
+ 45,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 20,
+ 46,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 21,
+ 47,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 22,
+ 48,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 23,
+ 49,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 24,
+ 50,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 25,
+ 51,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 26,
+ 56,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " gpt-4.1",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-19 17:50:59)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9fd98942d001elqd2sd8CZeOoA]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 27,
+ 66,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 1000,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "-20",
+ "OpencodeDiffDeleteText"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": 11
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "write 10 random words",
+ "",
+ "[`poem.md`](poem.md)",
+ "",
+ "----",
+ "",
+ "",
+ "Here are 10 random words:",
+ "",
+ "1. Lantern ",
+ "2. Whisper ",
+ "3. Velvet ",
+ "4. Orbit ",
+ "5. Timber ",
+ "6. Quiver ",
+ "7. Mosaic ",
+ "8. Ember ",
+ "9. Spiral ",
+ "10. Glimmer",
+ "",
+ "Let me know if you need them in a specific format or want to use them in a file!",
+ "",
+ "----",
+ "",
+ "",
+ "write 10 random words to the file",
+ "",
+ "----",
+ "",
+ "",
+ "I will write 10 random words to poem.md, each on a new line.",
+ "",
+ "Proceeding to update the file now.",
+ "",
+ "** write** `/home/francis/Projects/_nvim/opencode.nvim/poem.md`",
+ "",
+ "`````markdown",
+ "Lantern",
+ "Whisper",
+ "Velvet",
+ "Orbit",
+ "Timber",
+ "Quiver",
+ "Mosaic",
+ "Ember",
+ "Spiral",
+ "Glimmer",
+ "",
+ "`````",
+ "",
+ "** Created Snapshot** `c410b2b4`",
+ "",
+ "----",
+ "",
+ "",
+ "The file poem.md has been updated with 10 random words, each on a new line. Task complete! If you need anything else, let me know.",
+ "",
+ "----",
+ "",
+ "> 2 messages reverted, 4 tool calls reverted",
+ ">",
+ "> type `/redo` to restore.",
+ "",
+ " poem.md: -20",
+ ""
+ ],
+ "timestamp": 1770748581
+}
\ No newline at end of file
diff --git a/tests/data/selection.expected.json b/tests/data/selection.expected.json
index e950370c..5b771198 100644
--- a/tests/data/selection.expected.json
+++ b/tests/data/selection.expected.json
@@ -1 +1,393 @@
-{"timestamp":1766432128,"actions":[],"lines":["----","","","here's some context","","```txt","this is a string","```","","```txt","this is a selection test","```","","[`diff-test.txt`](diff-test.txt)","","----","","","I can see the file `/Users/cam/tmp/a/diff-test.txt` contains \"this is a string\" on line 1.","","The two selection contexts you provided show:","1. Current content: \"this is a string\"","2. Expected/desired content: \"this is a selection test\"","","Since I'm in read-only mode, I can only observe that there's a difference between what's currently in the file and what one of the selections indicates should be there.","",""],"extmarks":[[1,1,0,{"virt_text_repeat_linebreak":false,"virt_text_hide":false,"ns_id":3,"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-18 05:02:28)","OpencodeHint"],[" [msg_9f5b29fea001z6jYXF7CG9omHa]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":10,"right_gravity":true}],[2,2,0,{"virt_text_repeat_linebreak":true,"virt_text_hide":false,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[3,3,0,{"virt_text_repeat_linebreak":true,"virt_text_hide":false,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[4,4,0,{"virt_text_repeat_linebreak":true,"virt_text_hide":false,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[5,5,0,{"virt_text_repeat_linebreak":true,"virt_text_hide":false,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[6,6,0,{"virt_text_repeat_linebreak":true,"virt_text_hide":false,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[7,7,0,{"virt_text_repeat_linebreak":true,"virt_text_hide":false,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[8,8,0,{"virt_text_repeat_linebreak":true,"virt_text_hide":false,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[9,8,0,{"virt_text_repeat_linebreak":true,"virt_text_hide":false,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[10,9,0,{"virt_text_repeat_linebreak":true,"virt_text_hide":false,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[11,10,0,{"virt_text_repeat_linebreak":true,"virt_text_hide":false,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[12,11,0,{"virt_text_repeat_linebreak":true,"virt_text_hide":false,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[13,12,0,{"virt_text_repeat_linebreak":true,"virt_text_hide":false,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[14,12,0,{"virt_text_repeat_linebreak":true,"virt_text_hide":false,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[15,13,0,{"virt_text_repeat_linebreak":true,"virt_text_hide":false,"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true}],[16,16,0,{"virt_text_repeat_linebreak":false,"virt_text_hide":false,"ns_id":3,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["PLAN","OpencodeMessageRoleAssistant"],[" claude-sonnet-4.5","OpencodeHint"],[" (2025-10-18 05:02:28)","OpencodeHint"],[" [msg_9f5b2a039001xop8ITmXQq0Gjh]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":10,"right_gravity":true}]]}
+{
+ "actions": [],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-18 05:02:28)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9f5b29fea001z6jYXF7CG9omHa]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 2,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 3,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 4,
+ 4,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 5,
+ 5,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 6,
+ 6,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 7,
+ 7,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 8,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 9,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 10,
+ 9,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 11,
+ 10,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 12,
+ 11,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 13,
+ 12,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 14,
+ 12,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 15,
+ 13,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 16,
+ 16,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "PLAN",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " claude-sonnet-4.5",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-18 05:02:28)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9f5b2a039001xop8ITmXQq0Gjh]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "here's some context",
+ "",
+ "```txt",
+ "this is a string",
+ "```",
+ "",
+ "```txt",
+ "this is a selection test",
+ "```",
+ "",
+ "[`diff-test.txt`](diff-test.txt)",
+ "",
+ "----",
+ "",
+ "",
+ "I can see the file `/Users/cam/tmp/a/diff-test.txt` contains \"this is a string\" on line 1.",
+ "",
+ "The two selection contexts you provided show:",
+ "1. Current content: \"this is a string\"",
+ "2. Expected/desired content: \"this is a selection test\"",
+ "",
+ "Since I'm in read-only mode, I can only observe that there's a difference between what's currently in the file and what one of the selections indicates should be there.",
+ "",
+ ""
+ ],
+ "timestamp": 1770748581
+}
\ No newline at end of file
diff --git a/tests/data/shifting-and-multiple-perms.expected.json b/tests/data/shifting-and-multiple-perms.expected.json
index 686b2f64..611cad1c 100644
--- a/tests/data/shifting-and-multiple-perms.expected.json
+++ b/tests/data/shifting-and-multiple-perms.expected.json
@@ -1 +1,1097 @@
-{"actions":[],"extmarks":[[1,1,0,{"right_gravity":true,"virt_text_win_col":-3,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-17 01:05:49)","OpencodeHint"],[" [msg_9efb39d68001J2h30a50B2774b]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"priority":10}],[2,2,0,{"right_gravity":true,"virt_text_win_col":-3,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[3,3,0,{"right_gravity":true,"virt_text_win_col":-3,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[4,4,0,{"right_gravity":true,"virt_text_win_col":-3,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[5,5,0,{"right_gravity":true,"virt_text_win_col":-3,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[6,8,0,{"right_gravity":true,"virt_text_win_col":-3,"ns_id":3,"virt_text_hide":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["PLAN","OpencodeMessageRoleAssistant"],[" claude-sonnet-4.5","OpencodeHint"],[" (2025-10-17 01:05:50)","OpencodeHint"],[" [msg_9efb39dc3002f81rMRqF2WO1UU]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"priority":10}],[7,83,0,{"right_gravity":true,"virt_text_win_col":-3,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-17 01:07:23)","OpencodeHint"],[" [msg_9efb50a0b001WFK7AMDV45cF8Z]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"priority":10}],[8,84,0,{"right_gravity":true,"virt_text_win_col":-3,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[9,85,0,{"right_gravity":true,"virt_text_win_col":-3,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[10,88,0,{"right_gravity":true,"virt_text_win_col":-3,"ns_id":3,"virt_text_hide":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["PLAN","OpencodeMessageRoleAssistant"],[" claude-sonnet-4.5","OpencodeHint"],[" (2025-10-17 01:07:23)","OpencodeHint"],[" [msg_9efb50a2a002dzMgbQnasd86o1]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"priority":10}],[11,111,0,{"right_gravity":true,"virt_text_win_col":-3,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-17 01:08:01)","OpencodeHint"],[" [msg_9efb59d93001LSm9y0DS9p8cP6]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"priority":10}],[12,112,0,{"right_gravity":true,"virt_text_win_col":-3,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[13,113,0,{"right_gravity":true,"virt_text_win_col":-3,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[14,116,0,{"right_gravity":true,"virt_text_win_col":-3,"ns_id":3,"virt_text_hide":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["PLAN","OpencodeMessageRoleAssistant"],[" claude-sonnet-4.5","OpencodeHint"],[" (2025-10-17 01:08:01)","OpencodeHint"],[" [msg_9efb59db4002uWmyFRTjRIhIaQ]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"priority":10}],[15,125,0,{"right_gravity":true,"virt_text_win_col":-3,"ns_id":3,"virt_text_hide":false,"virt_text":[[" ","OpencodeMessageRoleSystem"],[" "],["SYSTEM","OpencodeMessageRoleSystem"],["","OpencodeHint"],["","OpencodeHint"],[" [permission-display-message]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"priority":10}],[16,127,0,{"right_gravity":true,"ns_id":3,"line_hl_group":"OpencodePermissionTitle","priority":4096}],[17,127,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[18,128,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[19,129,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[20,130,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[21,131,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[22,132,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[23,133,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[24,134,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[25,135,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[26,136,0,{"end_col":0,"hl_group":"OpencodeDiffAdd","right_gravity":true,"ns_id":3,"virt_text_hide":false,"end_row":137,"hl_eol":true,"end_right_gravity":false,"virt_text":[["+","OpencodeDiffAdd"]],"virt_text_pos":"overlay","virt_text_repeat_linebreak":false,"priority":5000}],[27,136,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[28,137,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[29,138,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[30,139,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[31,140,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[32,141,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[33,142,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[34,143,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[35,144,0,{"right_gravity":true,"ns_id":3,"line_hl_group":"OpencodeDialogOptionHover","priority":4096}],[36,144,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[37,144,2,{"right_gravity":true,"virt_text_hide":false,"ns_id":3,"virt_text":[["› ","OpencodeDialogOptionHover"]],"virt_text_pos":"overlay","virt_text_repeat_linebreak":false,"priority":4096}],[38,145,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[39,146,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[40,147,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}],[41,148,0,{"right_gravity":true,"virt_text_win_col":-2,"ns_id":3,"virt_text_hide":false,"virt_text":[["▌","OpencodePermissionBorder"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096}]],"timestamp":1769449853,"lines":["----","","","no, i want the extra line added when i've streamed the most recent part but i don't want it still there when i add the next part. i.e. i want an extra blank line at the end","","[`lua/opencode/ui/renderer.lua`](lua/opencode/ui/renderer.lua)","","----","","","Ah, I understand now! You want:","1. An extra blank line at the very end of the buffer when content has been streamed","2. But when **new** content is about to be added, remove that extra blank line first (so the new content doesn't have an awkward gap above it)","","This is a \"trailing spacer\" that should only exist when we're \"done\" with the current output, but gets removed before adding more.","","Here's the approach:","","## Solution","","Add tracking for whether a trailing blank line exists, and:","- **Add** a blank line after writing new content (in `_write_formatted_data`)","- **Remove** the trailing blank line before writing new content (also in `_write_formatted_data`)","","### Changes needed in `renderer.lua`:","","1. **Add state tracking** (after line 14):"," ```lua"," M._has_trailing_line = false"," ```","","2. **Reset the flag** in `M.reset()` (after line 21):"," ```lua"," M._has_trailing_line = false"," ```","","3. **Modify `_write_formatted_data`** (around line 247-276):"," - Before writing: remove trailing line if it exists"," - After writing: add a new trailing line"," "," ```lua"," function M._write_formatted_data(formatted_data)"," local buf = state.windows.output_buf"," local start_line = output_window.get_buf_line_count()"," "," -- Remove trailing blank line before adding new content"," if M._has_trailing_line and start_line > 0 then"," output_window.set_lines({}, start_line - 1, start_line)"," start_line = start_line - 1"," M._has_trailing_line = false"," end"," "," local new_lines = formatted_data.lines"," local extmarks = formatted_data.extmarks"," "," if #new_lines == 0 or not buf then"," return nil"," end"," "," -- [existing action extraction code...]"," "," output_window.set_lines(new_lines, start_line)"," output_window.set_extmarks(extmarks, start_line)"," "," -- Add trailing blank line after writing"," local end_line = start_line + #new_lines"," output_window.set_lines({''}, end_line)"," M._has_trailing_line = true"," "," return {"," line_start = start_line,"," line_end = start_line + #new_lines - 1,"," }"," end"," ```","","This way:","- ✅ Extra blank line appears after streaming content","- ✅ Gets removed automatically before next content is added","- ✅ No gap between messages","- ✅ Always has visual spacing at the bottom","","----","","","but i'd only want to do that for things added to the end","","----","","","Ah yes, you're right! The trailing blank line should only be added/removed when writing to the **end** of the buffer, not when doing replacements in the middle (like `_replace_part_in_buffer`).","","Let me trace through the code:","","1. **`_write_formatted_data`** - writes at end (line 247-276)","2. **`_insert_part_to_buffer`** - calls `_write_formatted_data`, so writes at end (line 282-300)","3. **`_replace_part_in_buffer`** - replaces in middle of buffer (line 307-353)","","So the logic should be:","- In **`_write_formatted_data`**: Remove trailing line before writing (if exists), then add it back after","- In **`_replace_part_in_buffer`**: Don't touch the trailing line at all","- In **`render_output`**: This sets the entire buffer, so no trailing line management needed","","The key insight is that `_write_formatted_data` is specifically for appending to the end (line 249: `start_line = output_window.get_buf_line_count()`), so that's the only place where we need to:","1. Remove the trailing blank line first (if it exists)","2. Write the new content","3. Add a new trailing blank line","","Does that match what you want? The trailing line only exists at the very end, and only gets managed when appending new content to the end.","","----","","","yes","","----","","","** edit** `/Users/cam/Dev/neovim-dev/opencode.nvim/lua/opencode/ui/renderer.lua`","","** edit** `/Users/cam/Dev/neovim-dev/opencode.nvim/lua/opencode/ui/renderer.lua`","","** edit** `/Users/cam/Dev/neovim-dev/opencode.nvim/lua/opencode/ui/renderer.lua`","","----","",""," Permission Required (1/3)",""," *edit* `Edit this file: /Users/cam/Dev/neovim-dev/opencode.nvim/lua/opencode/ui/renderer.lua`","","`````"," M._part_cache = {}"," M._prev_line_count = 0"," M._message_map = MessageMap.new()"," M._actions = {}"," M._has_trailing_line = false"," "," ---Reset renderer state"," function M.reset()"," M._part_cache = {}","","`````",""," 1. Allow once "," 2. Reject"," 3. Allow always","","Navigate: `j`/`k` or `↑`/`↓` Select: `` or `1-3`","",""]}
+{
+ "actions": [],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-17 01:05:49)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9efb39d68001J2h30a50B2774b]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 2,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 3,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 4,
+ 4,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 5,
+ 5,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 6,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "PLAN",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " claude-sonnet-4.5",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-17 01:05:50)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9efb39dc3002f81rMRqF2WO1UU]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 7,
+ 83,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-17 01:07:23)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9efb50a0b001WFK7AMDV45cF8Z]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 8,
+ 84,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 9,
+ 85,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 10,
+ 88,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "PLAN",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " claude-sonnet-4.5",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-17 01:07:23)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9efb50a2a002dzMgbQnasd86o1]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 11,
+ 111,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-17 01:08:01)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9efb59d93001LSm9y0DS9p8cP6]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 12,
+ 112,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 13,
+ 113,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 14,
+ 116,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "PLAN",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " claude-sonnet-4.5",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-17 01:08:01)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9efb59db4002uWmyFRTjRIhIaQ]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 15,
+ 125,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleSystem"
+ ],
+ [
+ " "
+ ],
+ [
+ "SYSTEM",
+ "OpencodeMessageRoleSystem"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " [permission-display-message]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 16,
+ 127,
+ 0,
+ {
+ "line_hl_group": "OpencodePermissionTitle",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true
+ }
+ ],
+ [
+ 17,
+ 127,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 18,
+ 128,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 19,
+ 129,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 20,
+ 130,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 21,
+ 131,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 22,
+ 132,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 23,
+ 133,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 24,
+ 134,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 25,
+ 135,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 26,
+ 136,
+ 0,
+ {
+ "end_col": 0,
+ "end_right_gravity": false,
+ "end_row": 137,
+ "hl_eol": true,
+ "hl_group": "OpencodeDiffAdd",
+ "ns_id": 3,
+ "priority": 5000,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "+",
+ "OpencodeDiffAdd"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "overlay",
+ "virt_text_repeat_linebreak": false
+ }
+ ],
+ [
+ 27,
+ 136,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 28,
+ 137,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 29,
+ 138,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 30,
+ 139,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 31,
+ 140,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 32,
+ 141,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 33,
+ 142,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 34,
+ 143,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 35,
+ 144,
+ 0,
+ {
+ "line_hl_group": "OpencodeDialogOptionHover",
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true
+ }
+ ],
+ [
+ 36,
+ 144,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 37,
+ 144,
+ 2,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "› ",
+ "OpencodeDialogOptionHover"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "overlay",
+ "virt_text_repeat_linebreak": false
+ }
+ ],
+ [
+ 38,
+ 145,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 39,
+ 146,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 40,
+ 147,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ],
+ [
+ 41,
+ 148,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodePermissionBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -2
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "no, i want the extra line added when i've streamed the most recent part but i don't want it still there when i add the next part. i.e. i want an extra blank line at the end",
+ "",
+ "[`lua/opencode/ui/renderer.lua`](lua/opencode/ui/renderer.lua)",
+ "",
+ "----",
+ "",
+ "",
+ "Ah, I understand now! You want:",
+ "1. An extra blank line at the very end of the buffer when content has been streamed",
+ "2. But when **new** content is about to be added, remove that extra blank line first (so the new content doesn't have an awkward gap above it)",
+ "",
+ "This is a \"trailing spacer\" that should only exist when we're \"done\" with the current output, but gets removed before adding more.",
+ "",
+ "Here's the approach:",
+ "",
+ "## Solution",
+ "",
+ "Add tracking for whether a trailing blank line exists, and:",
+ "- **Add** a blank line after writing new content (in `_write_formatted_data`)",
+ "- **Remove** the trailing blank line before writing new content (also in `_write_formatted_data`)",
+ "",
+ "### Changes needed in `renderer.lua`:",
+ "",
+ "1. **Add state tracking** (after line 14):",
+ " ```lua",
+ " M._has_trailing_line = false",
+ " ```",
+ "",
+ "2. **Reset the flag** in `M.reset()` (after line 21):",
+ " ```lua",
+ " M._has_trailing_line = false",
+ " ```",
+ "",
+ "3. **Modify `_write_formatted_data`** (around line 247-276):",
+ " - Before writing: remove trailing line if it exists",
+ " - After writing: add a new trailing line",
+ " ",
+ " ```lua",
+ " function M._write_formatted_data(formatted_data)",
+ " local buf = state.windows.output_buf",
+ " local start_line = output_window.get_buf_line_count()",
+ " ",
+ " -- Remove trailing blank line before adding new content",
+ " if M._has_trailing_line and start_line > 0 then",
+ " output_window.set_lines({}, start_line - 1, start_line)",
+ " start_line = start_line - 1",
+ " M._has_trailing_line = false",
+ " end",
+ " ",
+ " local new_lines = formatted_data.lines",
+ " local extmarks = formatted_data.extmarks",
+ " ",
+ " if #new_lines == 0 or not buf then",
+ " return nil",
+ " end",
+ " ",
+ " -- [existing action extraction code...]",
+ " ",
+ " output_window.set_lines(new_lines, start_line)",
+ " output_window.set_extmarks(extmarks, start_line)",
+ " ",
+ " -- Add trailing blank line after writing",
+ " local end_line = start_line + #new_lines",
+ " output_window.set_lines({''}, end_line)",
+ " M._has_trailing_line = true",
+ " ",
+ " return {",
+ " line_start = start_line,",
+ " line_end = start_line + #new_lines - 1,",
+ " }",
+ " end",
+ " ```",
+ "",
+ "This way:",
+ "- ✅ Extra blank line appears after streaming content",
+ "- ✅ Gets removed automatically before next content is added",
+ "- ✅ No gap between messages",
+ "- ✅ Always has visual spacing at the bottom",
+ "",
+ "----",
+ "",
+ "",
+ "but i'd only want to do that for things added to the end",
+ "",
+ "----",
+ "",
+ "",
+ "Ah yes, you're right! The trailing blank line should only be added/removed when writing to the **end** of the buffer, not when doing replacements in the middle (like `_replace_part_in_buffer`).",
+ "",
+ "Let me trace through the code:",
+ "",
+ "1. **`_write_formatted_data`** - writes at end (line 247-276)",
+ "2. **`_insert_part_to_buffer`** - calls `_write_formatted_data`, so writes at end (line 282-300)",
+ "3. **`_replace_part_in_buffer`** - replaces in middle of buffer (line 307-353)",
+ "",
+ "So the logic should be:",
+ "- In **`_write_formatted_data`**: Remove trailing line before writing (if exists), then add it back after",
+ "- In **`_replace_part_in_buffer`**: Don't touch the trailing line at all",
+ "- In **`render_output`**: This sets the entire buffer, so no trailing line management needed",
+ "",
+ "The key insight is that `_write_formatted_data` is specifically for appending to the end (line 249: `start_line = output_window.get_buf_line_count()`), so that's the only place where we need to:",
+ "1. Remove the trailing blank line first (if it exists)",
+ "2. Write the new content",
+ "3. Add a new trailing blank line",
+ "",
+ "Does that match what you want? The trailing line only exists at the very end, and only gets managed when appending new content to the end.",
+ "",
+ "----",
+ "",
+ "",
+ "yes",
+ "",
+ "----",
+ "",
+ "",
+ "** edit** `/Users/cam/Dev/neovim-dev/opencode.nvim/lua/opencode/ui/renderer.lua`",
+ "",
+ "** edit** `/Users/cam/Dev/neovim-dev/opencode.nvim/lua/opencode/ui/renderer.lua`",
+ "",
+ "** edit** `/Users/cam/Dev/neovim-dev/opencode.nvim/lua/opencode/ui/renderer.lua`",
+ "",
+ "----",
+ "",
+ "",
+ " Permission Required (1/3)",
+ "",
+ " *edit* `Edit this file: /Users/cam/Dev/neovim-dev/opencode.nvim/lua/opencode/ui/renderer.lua`",
+ "",
+ "`````",
+ " M._part_cache = {}",
+ " M._prev_line_count = 0",
+ " M._message_map = MessageMap.new()",
+ " M._actions = {}",
+ " M._has_trailing_line = false",
+ " ",
+ " ---Reset renderer state",
+ " function M.reset()",
+ " M._part_cache = {}",
+ "",
+ "`````",
+ "",
+ " 1. Allow once ",
+ " 2. Reject",
+ " 3. Allow always",
+ "",
+ "Navigate: `j`/`k` or `↑`/`↓` Select: `` or `1-3`",
+ "",
+ ""
+ ],
+ "timestamp": 1770748581
+}
\ No newline at end of file
diff --git a/tests/data/simple-session.expected.json b/tests/data/simple-session.expected.json
index ed346f39..bd107d06 100644
--- a/tests/data/simple-session.expected.json
+++ b/tests/data/simple-session.expected.json
@@ -1 +1,221 @@
-{"actions":[],"timestamp":1766432128,"extmarks":[[1,1,0,{"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-10 19:18:25)","OpencodeHint"],[" [msg_9cf8f64de0016tbfTQqWMydbdr]","OpencodeHint"]],"right_gravity":true,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"priority":10,"virt_text_hide":false,"virt_text_win_col":-3,"ns_id":3}],[2,2,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096,"virt_text_hide":false,"virt_text_win_col":-3,"ns_id":3}],[3,3,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096,"virt_text_hide":false,"virt_text_win_col":-3,"ns_id":3}],[4,4,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096,"virt_text_hide":false,"virt_text_win_col":-3,"ns_id":3}],[5,5,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096,"virt_text_hide":false,"virt_text_win_col":-3,"ns_id":3}],[6,6,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096,"virt_text_hide":false,"virt_text_win_col":-3,"ns_id":3}],[7,7,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"priority":4096,"virt_text_hide":false,"virt_text_win_col":-3,"ns_id":3}],[8,10,0,{"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" claude-sonnet-4","OpencodeHint"],[" (2025-10-10 19:18:25)","OpencodeHint"],[" [msg_9cf8f6549001tpoRuqkwS4Rxtl]","OpencodeHint"]],"right_gravity":true,"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"priority":10,"virt_text_hide":false,"virt_text_win_col":-3,"ns_id":3}]],"lines":["----","","","only answer the following, nothing else:","","1","","[`a-empty.txt`](a-empty.txt)","","----","","","1","",""]}
+{
+ "actions": [],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-10 19:18:25)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9cf8f64de0016tbfTQqWMydbdr]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 2,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 3,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 4,
+ 4,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 5,
+ 5,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 6,
+ 6,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 7,
+ 7,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 8,
+ 10,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " claude-sonnet-4",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-10 19:18:25)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9cf8f6549001tpoRuqkwS4Rxtl]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "only answer the following, nothing else:",
+ "",
+ "1",
+ "",
+ "[`a-empty.txt`](a-empty.txt)",
+ "",
+ "----",
+ "",
+ "",
+ "1",
+ "",
+ ""
+ ],
+ "timestamp": 1770748581
+}
\ No newline at end of file
diff --git a/tests/data/tool-invalid.expected.json b/tests/data/tool-invalid.expected.json
index 92886a00..222f8caf 100644
--- a/tests/data/tool-invalid.expected.json
+++ b/tests/data/tool-invalid.expected.json
@@ -1 +1,178 @@
-{"timestamp":1766432128,"actions":[],"lines":["----","","","** tool** `invalid`","","> [!ERROR]",">","> Invalid input for tool edit: JSON parsing failed: Text: {\"filePath\": \"/Users/cam/Dev/neovim-dev/opencode.nvim/lua/opencode/ui/streaming_renderer.lua\", \"newString\": \"---Event handler for permission.replied events\\n---Re-renders part after permission is resolved\\n---@param event table Event object\\nfunctio.","> Error message: JSON Parse error: Unterminated string","",""],"extmarks":[[1,1,0,{"virt_text_repeat_linebreak":false,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" claude-sonnet-4.5","OpencodeHint"],[" (2025-10-13 20:10:06)","OpencodeHint"],[" [msg_9df31cc90001HGn2UbFUgqJnLr]","OpencodeHint"]],"ns_id":3,"virt_text_hide":false,"priority":10,"right_gravity":true,"virt_text_win_col":-3,"virt_text_pos":"win_col"}],[2,3,0,{"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"priority":4096,"right_gravity":true,"virt_text_win_col":-1,"virt_text_pos":"win_col"}],[3,4,0,{"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"priority":4096,"right_gravity":true,"virt_text_win_col":-1,"virt_text_pos":"win_col"}],[4,5,0,{"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"priority":4096,"right_gravity":true,"virt_text_win_col":-1,"virt_text_pos":"win_col"}],[5,6,0,{"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"priority":4096,"right_gravity":true,"virt_text_win_col":-1,"virt_text_pos":"win_col"}],[6,7,0,{"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"priority":4096,"right_gravity":true,"virt_text_win_col":-1,"virt_text_pos":"win_col"}],[7,8,0,{"virt_text_repeat_linebreak":true,"virt_text":[["▌","OpencodeToolBorder"]],"ns_id":3,"virt_text_hide":false,"priority":4096,"right_gravity":true,"virt_text_win_col":-1,"virt_text_pos":"win_col"}]]}
\ No newline at end of file
+{
+ "actions": [],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "BUILD",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " claude-sonnet-4.5",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-13 20:10:06)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9df31cc90001HGn2UbFUgqJnLr]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 3,
+ 4,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 4,
+ 5,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 5,
+ 6,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 6,
+ 7,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ],
+ [
+ 7,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeToolBorder"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -1
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "** tool** `invalid`",
+ "",
+ "> [!ERROR]",
+ ">",
+ "> Invalid input for tool edit: JSON parsing failed: Text: {\"filePath\": \"/Users/cam/Dev/neovim-dev/opencode.nvim/lua/opencode/ui/streaming_renderer.lua\", \"newString\": \"---Event handler for permission.replied events\\n---Re-renders part after permission is resolved\\n---@param event table Event object\\nfunctio.",
+ "> Error message: JSON Parse error: Unterminated string",
+ "",
+ ""
+ ],
+ "timestamp": 1770748582
+}
\ No newline at end of file
diff --git a/tests/data/updating-text.expected.json b/tests/data/updating-text.expected.json
index 3ce892ea..bbff6aa0 100644
--- a/tests/data/updating-text.expected.json
+++ b/tests/data/updating-text.expected.json
@@ -1 +1,228 @@
-{"timestamp":1769091027,"actions":[],"lines":["----","","","What would a new neovim lua plugin look like?","","[`a-empty.txt`](a-empty.txt)","","----","","","A new Neovim Lua plugin typically follows this structure:","","```","plugin-name/","├── lua/","│ └── plugin-name/","│ ├── init.lua -- Main entry point","│ ├── config.lua -- Configuration handling","│ └── utils.lua -- Utility functions","├── plugin/","│ └── plugin-name.lua -- Plugin registration","└── README.md","```","","**Minimal example:**","","`plugin/example.lua`:","```lua","if vim.g.loaded_example then"," return","end","vim.g.loaded_example = 1","","vim.api.nvim_create_user_command('Example', function()"," require('example').hello()","end, {})","```","","`lua/example/init.lua`:","```lua","local M = {}","","M.setup = function(opts)"," opts = opts or {}"," -- Handle configuration","end","","M.hello = function()"," print(\"Hello from my plugin!\")","end","","return M","```","","Key components:","- Use `vim.api` for Neovim API calls","- Provide a `setup()` function for configuration","- Create user commands with `nvim_create_user_command`","- Use autocommands with `nvim_create_autocmd`","- Follow Lua module patterns with `local M = {}`","",""],"extmarks":[[1,1,0,{"virt_text":[["▌ ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-10 22:06:43)","OpencodeHint"],[" [msg_9d0297a630014CA5ly3Vvw8Kt5]","OpencodeHint"]],"ns_id":3,"virt_text_pos":"win_col","right_gravity":true,"priority":10,"virt_text_win_col":-3,"virt_text_repeat_linebreak":false,"virt_text_hide":false}],[2,2,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_pos":"win_col","right_gravity":true,"priority":4096,"virt_text_win_col":-3,"virt_text_repeat_linebreak":true,"virt_text_hide":false}],[3,3,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_pos":"win_col","right_gravity":true,"priority":4096,"virt_text_win_col":-3,"virt_text_repeat_linebreak":true,"virt_text_hide":false}],[4,4,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_pos":"win_col","right_gravity":true,"priority":4096,"virt_text_win_col":-3,"virt_text_repeat_linebreak":true,"virt_text_hide":false}],[5,5,0,{"virt_text":[["▌","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_pos":"win_col","right_gravity":true,"priority":4096,"virt_text_win_col":-3,"virt_text_repeat_linebreak":true,"virt_text_hide":false}],[6,8,0,{"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["PLAN","OpencodeMessageRoleAssistant"],[" claude-sonnet-4","OpencodeHint"],[" (2025-10-10 22:06:43)","OpencodeHint"],[" [msg_9d0297ab3001UGZU9fDJM4Y75w]","OpencodeHint"]],"ns_id":3,"virt_text_pos":"win_col","right_gravity":true,"priority":10,"virt_text_win_col":-3,"virt_text_repeat_linebreak":false,"virt_text_hide":false}]]}
+{
+ "actions": [],
+ "extmarks": [
+ [
+ 1,
+ 1,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌ ",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ " "
+ ],
+ [
+ "USER",
+ "OpencodeMessageRoleUser"
+ ],
+ [
+ "",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-10 22:06:43)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9d0297a630014CA5ly3Vvw8Kt5]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 2,
+ 2,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 3,
+ 3,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 4,
+ 4,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 5,
+ 5,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 4096,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ "▌",
+ "OpencodeMessageRoleUser"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": true,
+ "virt_text_win_col": -3
+ }
+ ],
+ [
+ 6,
+ 8,
+ 0,
+ {
+ "ns_id": 3,
+ "priority": 10,
+ "right_gravity": true,
+ "virt_text": [
+ [
+ " ",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " "
+ ],
+ [
+ "PLAN",
+ "OpencodeMessageRoleAssistant"
+ ],
+ [
+ " claude-sonnet-4",
+ "OpencodeHint"
+ ],
+ [
+ " (2025-10-10 22:06:43)",
+ "OpencodeHint"
+ ],
+ [
+ " [msg_9d0297ab3001UGZU9fDJM4Y75w]",
+ "OpencodeHint"
+ ]
+ ],
+ "virt_text_hide": false,
+ "virt_text_pos": "win_col",
+ "virt_text_repeat_linebreak": false,
+ "virt_text_win_col": -3
+ }
+ ]
+ ],
+ "lines": [
+ "----",
+ "",
+ "",
+ "What would a new neovim lua plugin look like?",
+ "",
+ "[`a-empty.txt`](a-empty.txt)",
+ "",
+ "----",
+ "",
+ "",
+ "A new Neovim Lua plugin typically follows this structure:",
+ "",
+ "```",
+ "plugin-name/",
+ "├── lua/",
+ "│ └── plugin-name/",
+ "│ ├── init.lua -- Main entry point",
+ "│ ├── config.lua -- Configuration handling",
+ "│ └── utils.lua -- Utility functions",
+ "├── plugin/",
+ "│ └── plugin-name.lua -- Plugin registration",
+ "└── README.md",
+ "```",
+ "",
+ "**Minimal example:**",
+ "",
+ "`plugin/example.lua`:",
+ "```lua",
+ "if vim.g.loaded_example then",
+ " return",
+ "end",
+ "vim.g.loaded_example = 1",
+ "",
+ "vim.api.nvim_create_user_command('Example', function()",
+ " require('example').hello()",
+ "end, {})",
+ "```",
+ "",
+ "`lua/example/init.lua`:",
+ "```lua",
+ "local M = {}",
+ "",
+ "M.setup = function(opts)",
+ " opts = opts or {}",
+ " -- Handle configuration",
+ "end",
+ "",
+ "M.hello = function()",
+ " print(\"Hello from my plugin!\")",
+ "end",
+ "",
+ "return M",
+ "```",
+ "",
+ "Key components:",
+ "- Use `vim.api` for Neovim API calls",
+ "- Provide a `setup()` function for configuration",
+ "- Create user commands with `nvim_create_user_command`",
+ "- Use autocommands with `nvim_create_autocmd`",
+ "- Follow Lua module patterns with `local M = {}`",
+ "",
+ ""
+ ],
+ "timestamp": 1770748582
+}
\ No newline at end of file
diff --git a/tests/manual/renderer_replay.lua b/tests/manual/renderer_replay.lua
index 28ef9060..0f85af32 100644
--- a/tests/manual/renderer_replay.lua
+++ b/tests/manual/renderer_replay.lua
@@ -201,7 +201,7 @@ function M.save_output(filename)
snapshot = M.normalize_file_paths(snapshot)
if filename then
- local json = vim.json.encode(snapshot)
+ local json = vim.json.encode(snapshot, { indent = ' ', sort_keys = true })
local f = io.open(filename, 'w')
if not f then