Files
qode/AGENTS.md
T
2026-10-30 20:50:04 +03:00

6.2 KiB

AGENTS.md

Instructions for AI coding agents working on this repository. Read this file before changing code. The rules below are architectural requirements, not suggestions.

Project shape

Path Responsibility
src/api.rs AppApi / PanelApi — the single control surface of the application
src/script.rs Lua engine; publishes app, include, and require
src/keymap.rs Key binding parsing (KeyBinding) and dispatch (KeyMap)
src/app.rs GPUI view, rendering, event wiring
src/editor.rs Workspace, documents, tabs
src/panel.rs PanelState for left/right/bottom panels
src/lsp.rs LSP server manager
src/constants.rs CLI arguments and script directory
init.lua Example startup script (also a usage reference)
DOCS.md User-facing Lua API documentation

1. AppApi is the center of the application

  • AppApi (in src/api.rs) is the one object through which the application is controlled. All operations on documents, tabs, panels, the window, syntax highlighting, key bindings, and LSP go through it.
  • Shared state is held as Rc<RefCell<_>> handles (workspace, keymap, panels, LSP manager). The UI and AppApi must observe the same instances; never create a second copy of the state.
  • Rust code that needs to act on the application should call AppApi::global() (or an AppApi instance passed in) instead of mutating Workspace, PanelState, KeyMap, or LspManager directly.
  • Methods that are implementation details of AppApi stay private or are marked #[lua(skip)]. Do not add a second, parallel control path.

2. Every AppApi capability is available from Lua

  • Everything in the impl AppApi block annotated with #[mlua::userdata_impl] is automatically exposed as app:method(...).
  • When adding functionality, add it to AppApi and expose it to Lua at the same time. An operation that a user can trigger in the UI must also be callable from a Lua script.
  • Use #[lua(infallible)] where the method cannot fail, and return mlua::Result / convert errors to mlua::Error::RuntimeError otherwise.
  • Generic Rust methods are not exported. Add a thin non-generic Lua wrapper, following the existing pattern: save / lua_save, open / lua_open, set_active_text / lua_set_active_text, set_language / lua_set_language.
  • Use #[lua(name = "...")] when the Lua name should differ from the Rust name (for example active_tab_index → active_tab).
  • Lua API naming: lower snake_case, tabs and indices are zero-based, panels are accessed as app.left_panel, app.right_panel, app.bottom_panel.

3. All UI actions and keyboard shortcuts go through the API

UI actions

  • UI event handlers and rendered controls must invoke AppApi methods, not manipulate state directly. Examples:
    • window close button → app:close() (i.e. AppApi::close)
    • minimize button → app:minimize()
    • maximize / restore → app:toggle_maximize() or app:set_maximized(bool); read the current state with app:is_maximized()
    • tab close button → app:close_tab(index)
    • "new tab" button → app:open_tab()
    • panel toggles → app.right_panel:toggle() and friends
  • Rendering code may read state (for example workspace.borrow() to draw the active document), but must not mutate it. Mutations belong to AppApi.
  • Window operations are queued as WindowCommands and applied by apply_window_commands; keep this mechanism as the only way the UI and Lua request window changes.
  • If an external component (for example gpui_kit::component::TitleBar) performs an action internally, do not leave it as a separate control path: intercept the action or replace the component so that it calls AppApi.

Keyboard shortcuts

  • Every key binding must be registered through AppApi::map_key / KeyMap. There must be no hard-coded shortcuts that scripts cannot inspect, override, or remove.
  • Existing hard-coded checks such as is_save_shortcut and is_completion_shortcut in src/app.rs are technical debt: when touching this area, move those defaults into the KeyMap mechanism so they can be rebound from Lua.
  • Default bindings should be installed through the same mechanism that scripts use (or a documented equivalent), so that app:map_key(...) can replace them. Rebinding the same chord must replace the previous handler.
  • Dispatch order matters: the key interceptor runs before key bindings, and dispatch_keymap is used for both key down and key up (<...> vs !key). Preserve this behavior.
  • Any KeyMap change must keep the documented chord syntax working: a, 1, !a, <S-c>, <C-z>, <A-!r>, named keys (case-insensitive).
  • Editor text input itself is not a shortcut, but all app-level commands (save, close, panels, completion popup navigation, etc.) must be remappable.

4. Keep DOCS.md in sync

DOCS.md is the source of truth for the Lua API. In the same change that modifies the public surface, update the docs:

  • added/removed/renamed AppApi or PanelApi methods;
  • changed arguments, return values, or error behavior;
  • new supported languages, LSP configuration fields, CLI flags, or include/require behavior;
  • changed default shortcuts or their syntax.

Also update the usage comments in init.lua when they describe behavior that changed. Documentation must describe the code as it actually behaves — no aspirational APIs.

Conventions

  • Keep changes focused and consistent with the existing style; comments and user-facing documentation are written in Russian.
  • Rust API docs use ///; write them for every new public method.
  • Validate with cargo fmt and cargo test, then cargo build if behavior changed. Do not commit unless explicitly asked.

Checklist

Before finishing a change, verify:

  • The new behavior is implemented in AppApi, not in a UI handler.
  • The operation is callable from Lua and has a documented signature.
  • No new hard-coded keyboard shortcut bypasses KeyMap.
  • UI controls call the corresponding AppApi method.
  • DOCS.md (and init.lua comments if needed) are updated.
  • cargo fmt and cargo test pass (or explain why they could not run).