Emacs Context Navigator is a lightweight, project‑aware context manager and sidebar for Emacs.
The idea: practice “context engineering”. Instead of keeping task state, open files, buffer selections, and notes in your head, externalize them into clear, reusable context groups per project (or globally). Switch context instantly, reduce cognitive load, and keep your focus on the work.
- View to browse items and groups, with a compact header-line toolbar
- Project‑aware, optional auto‑switch on buffer/project change
- One‑way integration with GPTel (push current items → GPTel)
- Per‑group Undo/Redo (history) with header‑line controls
- Async, per‑group persistence with progress and spinner
- Stats footer (counts, size, token estimates) — togglable
- Dired‑aware “Universal Add”, globs, and “add from text”
Repository: https://github.com/11111000000/context-navigator
- Emacs 29.1+ (recommended 30.1+)
- transient 0.3.0+ (for the global menu)
- Optional:
- gptel (for one‑way push)
- project.el or projectile (for project detection/auto‑switch)
- all-the-icons (for icons in the sidebar; remember to install fonts)
Not on MELPA. Use a local checkout or straight.el from GitHub.
- Local checkout + use-package (recommended)
(use-package context-navigator
:load-path "~/Code/context-navigator/lisp"
:custom
;; Optional, but handy: set a global key for the transient menu
(context-navigator-global-key "C-c n")
;; Recommended defaults
(context-navigator-autoload t)
(context-navigator-autosave t)
:config
(context-navigator-mode 1))
- straight.el (from GitHub)
(use-package context-navigator
:straight (context-navigator
:type git
:host github
:repo "11111000000/context-navigator")
:custom
(context-navigator-global-key "C-c n")
(context-navigator-autoload t)
(context-navigator-autosave t)
:config
(context-navigator-mode 1))
Notes:
- If you don’t want a global binding, keep
context-navigator-global-key
as nil and useM-x context-navigator-transient
. - If you enable icons, install fonts once:
M-x all-the-icons-install-fonts
.
- Enable the mode:
M-x context-navigator-mode
(or add(context-navigator-mode 1)
to your init) - Open the Navigator right away:
M-x context-navigator-start
(default display: buffer/magit-like; switch with M in transient) - Press your global key, e.g.,
C-c n
, then:- n — toggle Navigator; M — Display Mode (buffer/sidebar)
- a — Add (universal): region/file/buffer or Dired selection
- f — Add files by glob (from minibuffer)
- t — Add files from text (extracts paths from region/buffer)
- g — show groups
- G/A — toggle push→gptel / auto‑project
- R — Occam filter (org-mode): minimize enabled items for the task
- P/C — Push now / Clear gptel
- Press ? in the sidebar for localized, column‑formatted help
- Switch between task groups (project‑centric): “research”, “bug‑123”, “release”.
- Auto‑project switching: follows your current file/gptel/Dired buffers across projects.
- LLM sessions: push enabled items to GPTel on demand or automatically; return to saved groups anytime.
- Adding context:
- “Universal Add” (from Dired/region/file/buffer)
- Add by mask (glob)
- Add from text (extract file‑like tokens and resolve)
- Per-task groups with GPTel:
- Create a group per task/issue; add files, buffers, and selections that matter.
- Toggle auto-push ON and keep chatting in GPTel (or gptel-aibo minor mode in org).
- The modeline in the Navigator shows the full path at point; indicators (●/○) reflect actual presence in GPTel.
- Using gptel-aibo:
- gptel-aibo buffers are treated as “interesting” for auto-project switching; Navigator will stick to the correct project while you chat.
- Default-directory of gptel-aibo buffers is respected; switching windows updates Navigator’s project and groups list.
- Trimming context and saving tokens:
- Use the Occam filter (R in the transient, org-mode) to keep only essential items enabled for the current task.
- The Stats footer (s) shows rough token estimates for enabled vs total; combine with Occam to control budget.
- Selections and edits:
- Add precise regions from files as “selection” items; Occam handles them safely.
- Quickly enable/disable per item with SPC/t; Undo/Redo per group is available via header toolbar (↶/↷).
- Multi-project work:
- Navigator “sticks” to the last meaningful root and avoids flicker to global; throttle is configurable.
- Use p in the transient to switch explicitly to the current buffer’s project when needed.
- Sidebar
- Title inside the buffer shows “[project: group]” in Items view; Groups view shows “[project]”.
- Toolbar in the header-line (clickable and TAB-reachable) contains all toggles and actions (shows graphical icons when all-the-icons is available; otherwise compact labels in brackets):
- [→] push→gptel on/off
- [A] auto-project on/off
- [↶]/[↷] Undo/Redo history
- [O] Open buffers (background; dynamic count; remote-aware)
- [K] Close buffers (belonging to the current group)
- [P] Push now
- [T] Toggle all in gptel (“Enable all gptel” when everything is disabled; otherwise “Disable all in gptel”)
- Per-point status is shown in the modeline; the buffer footer is minimal. In items view the modeline shows the full path of the item at point; in groups view it shows “Display — Description” when a description is set.
- Indicators (green/gray) show whether an item is present in GPTel (when indicators are enabled).
- Transient menu (
C-c n
by default)- Quick access to panel, groups, add, GPTel toggles, and logs.
- Navigation
- Items and groups are interactive. Use TAB/Shift‑TAB to move between toggles, actions, items, and groups.
- Ret/Space: visit/preview. j/k or n/p: next/prev.
Examples:
- Open all context buffers for a group, then Push now to ground a GPTel chat.
- Dired: mark files and “a” (Universal Add) to collect them; if directories are included, confirm via preview.
- Global (context-navigator-mode)
- Your chosen key (e.g., C-c n) →
context-navigator-transient
- Your chosen key (e.g., C-c n) →
- Transient (selected)
- Panel/Project: n (toggle sidebar), p (switch to current buffer’s project)
- Context/Groups: g (groups list), X (unload context)
- Actions: a (Add universal), f (Add by mask), t (Add from text), o (Open buffers)
- GPTel: G (toggle push), A (toggle auto‑project), P (push now), C (clear gptel)
- Logs: D (toggle logs), L (open logs), K (clear logs), V (set level), F (toggle file logging)
- Sidebar (context-navigator-view-mode)
- RET / l: activate (visit item/open group)
- v: preview (other window)
- n/p/j/k: next/previous
- SPC / t: toggle enabled for item at point
- d: delete (item or group, depending on view)
- g: refresh (items or groups)
- h / u: go up (toggle items ↔ groups)
- G: show groups list
- a / r / e / c: add / rename / edit description / duplicate group (groups view)
- x / A: toggle push→gptel / auto‑project
- U: unload context (switch to global)
- P / C: push now / clear gptel
- O / o: open all context buffers (background)
- K: close all context buffers
- E: clear current group
- s: toggle Stats footer
- TAB / S-TAB: jump across toggles/actions/items/groups
- q: quit, ?: menu/help
Quality‑of‑life:
delete-other-windows
is remapped to close sidebar windows first (keeps layout).- Optional: protect window balancing while the sidebar is visible.
Below are all public settings collected from the source, grouped by module. “Default” reflects the code defaults, not your current values.
Variable | Type | Default | Description | Module/File |
---|---|---|---|---|
context-navigator-auto-refresh | boolean | t | Auto refresh model/sidebar after external changes | core/context-navigator-core.el |
context-navigator-global-key | string or nil | nil | Global key for transient (e.g., “C-c n”); nil = no binding | core/context-navigator-core.el |
context-navigator-view-width | integer | 42 | Sidebar width in columns | core/context-navigator-core.el |
context-navigator-max-filename-length | integer | 64 | Max display length for file names | core/context-navigator-core.el |
context-navigator-context-switch-interval | number | 0.7 | Throttle interval (s) for project auto‑switch | core/context-navigator-core.el |
context-navigator-context-load-batch-size | integer | 64 | Batch size for async context load | core/context-navigator-core.el |
context-navigator-gptel-apply-batch-size | integer | 20 | Items per tick when pushing to GPTel in background | core/context-navigator-core.el |
context-navigator-gptel-apply-batch-interval | number | 0.05 | Delay (s) between GPTel apply batches | core/context-navigator-core.el |
context-navigator-gptel-require-visible-window | boolean | nil | Defer GPTel apply until a GPTel window is visible | core/context-navigator-core.el |
context-navigator-gptel-visible-poll-interval | number | 0.5 | Poll interval (s) for GPTel visibility when deferred | core/context-navigator-core.el |
context-navigator-autosave | boolean | t | Autosave group file on model refresh | core/context-navigator-core.el |
context-navigator-autosave-debounce | number | 0.5 | Debounce (s) for autosave | core/context-navigator-core.el |
context-navigator-autoload | boolean | t | Autoload context on project switch | core/context-navigator-core.el |
context-navigator-default-push-to-gptel | boolean | nil | Initial session state: push to GPTel | core/context-navigator-core.el |
context-navigator-default-auto-project-switch | boolean | t | Initial session state: auto‑project switch | core/context-navigator-core.el |
context-navigator-dir-name | string | “.context” | Project subdir for context files | core/context-navigator-core.el |
context-navigator-context-file-name | string | “context.el” | Legacy single‑file name (still used for compatibility paths) | core/context-navigator-core.el |
context-navigator-global-dir | directory | ~/.context | Global context directory | core/context-navigator-core.el |
context-navigator-create-default-group-file | boolean | t | Ensure default group file exists on first use | core/context-navigator-core.el |
context-navigator-protect-sidebar-windows | boolean | t | Protect sidebar from window‑balancing (skip balance while visible) | core/context-navigator-core.el |
Constants:
Variable | Type | Default | Description | Module/File |
---|---|---|---|---|
context-navigator-persist-version | constant | 3 | Persist format version used across modules | core/context-navigator-core.el |
Variable | Type | Default | Description | Module/File | ||||
---|---|---|---|---|---|---|---|---|
context-navigator-auto-open-groups-on-error | boolean | t | Auto‑open groups list when a group fails to load | sidebar/context-navigator-view.el | ||||
context-navigator-highlight-active-group | boolean | t | Highlight active group in groups list | sidebar/context-navigator-view.el | ||||
context-navigator-controls-style | choice (auto | icons | text) | icons | Labels style for toggles/actions | sidebar/context-navigator-view.el | ||
context-navigator-openable-count-ttl | number | 1.0 | Cache TTL (s) for openable counter | sidebar/context-navigator-view.el | ||||
context-navigator-openable-soft-cap | integer | 100 | Soft cap for counting openable buffers | sidebar/context-navigator-view.el | ||||
context-navigator-openable-remote-mode | choice (lazy | strict | off) | lazy | How to treat remote files in “Open buffers” | sidebar/context-navigator-view.el | ||
context-navigator-gptel-indicator-poll-interval | number | 0 | Polling interval (s) for GPTel indicators (0 to disable) | sidebar/context-navigator-view.el | ||||
context-navigator-view-spinner-frames | list of strings | ⠋…⠏ | Frames for the loading spinner | sidebar/context-navigator-view.el | ||||
context-navigator-view-spinner-interval | number | 0.1 | Spinner animation interval (s) | sidebar/context-navigator-view.el | ||||
context-navigator-view-spinner-degrade-threshold | number | 0.25 | Degrade to static indicator if timer slips beyond this (s) | sidebar/context-navigator-view.el |
Variable | Type | Default | Description | Module/File | |||
---|---|---|---|---|---|---|---|
context-navigator-render-show-path | boolean | nil | Show item path in right column | render/context-navigator-render.el | |||
context-navigator-render-truncate-name | integer | 64 | Max display length for item names | render/context-navigator-render.el | |||
context-navigator-render-indicator-style | choice (auto | icons | text | off) | text | GPTel presence indicators style | render/context-navigator-render.el |
Variable | Type | Default | Description | Module/File |
---|---|---|---|---|
context-navigator-enable-icons | boolean | t | Enable icons in the sidebar | icons/context-navigator-icons.el |
context-navigator-icons-disable-on-remote | boolean | t | Disable icons on remote/TRAMP | icons/context-navigator-icons.el |
Variable | Type | Default | Description | Module/File |
---|---|---|---|---|
context-navigator-project-nonfile-modes | list of modes | (gptel-mode comint-mode … dired-mode …) | Non‑file modes that can represent real project context | project/context-navigator-project.el |
context-navigator-project-stick-to-last-root | boolean | t | Stick to last known root instead of transient switches to global | project/context-navigator-project.el |
Variable | Type | Default | Description | Module/File | ||
---|---|---|---|---|---|---|
context-navigator-add-paths-limit | integer | 50 | Max files to add in a single operation | add-paths/context-navigator-add-paths.el | ||
context-navigator-add-paths-index-cache-ttl | number | 30.0 | TTL (s) for project file index cache | add-paths/context-navigator-add-paths.el | ||
context-navigator-add-paths-case-sensitive | choice (auto | on | off) | on | Case sensitivity policy for basename matching | add-paths/context-navigator-add-paths.el |
context-navigator-add-paths-ignore-gitignored | boolean | t | Prefer sources that respect .gitignore | add-paths/context-navigator-add-paths.el | ||
context-navigator-add-paths-exclude-dotdirs | boolean | t | Exclude dot-directories in fallback recursion | add-paths/context-navigator-add-paths.el | ||
context-navigator-add-paths-fallback-exclude | list of strings | (node_modules dist build target) | Directory names excluded in fallback recursion | add-paths/context-navigator-add-paths.el | ||
context-navigator-mask-include-dotfiles | boolean | nil | Include dotfiles without explicit dot component | add-paths/context-navigator-add-paths.el | ||
context-navigator-mask-enable-remote | boolean | nil | Allow TRAMP mask expansion | add-paths/context-navigator-add-paths.el | ||
context-navigator-mask-globstar | boolean | t | Enable ** (globstar) | add-paths/context-navigator-add-paths.el |
Variable | Type | Default | Description | Module/File |
---|---|---|---|---|
context-navigator-max-file-size | integer | (* 1 1024 1024) | Max file size (bytes) for recursive adds/filters | transient/context-navigator-transient.el |
Variable | Type | Default | Description | Module/File |
---|---|---|---|---|
context-navigator-log-enabled | boolean | nil | Enable logging | log/context-navigator-log.el |
context-navigator-log-level | choice (:error :warn :info :debug :trace) | :info | Minimal level to log when enabled | log/context-navigator-log.el |
context-navigator-log-auto-open-on-error | boolean | t | Open log buffer automatically on errors | log/context-navigator-log.el |
context-navigator-log-buffer-name | string | ”Context Navigator Log” | Log buffer name | log/context-navigator-log.el |
context-navigator-log-max-lines | integer | 5000 | Trim log to at most N lines | log/context-navigator-log.el |
context-navigator-log-truncate-length | integer | 800 | Truncate long messages (0/nil = no truncation) | log/context-navigator-log.el |
context-navigator-log-file-enable | boolean | nil | Also append each line to a persistent file | log/context-navigator-log.el |
context-navigator-log-file | file or nil | nil | Path to persistent log file | log/context-navigator-log.el |
Variable | Type | Default | Description | Module/File |
---|---|---|---|---|
context-navigator-language | choice (auto en ru fr de es) | auto | UI language; auto detects from locale | i18n/context-navigator-i18n.el |
Variable | Type | Default | Description | Module/File |
---|---|---|---|---|
context-navigator-view-headerline-enable | boolean | t | Show Navigator controls in the buffer header-line | headerline/context-navigator-headerline.el |
Variable | Type | Default | Description | Module/File |
---|---|---|---|---|
context-navigator-view-modeline-enable | boolean | t | Show minimal per-point status in the modeline | modeline/context-navigator-view-modeline.el |
context-navigator-view-modeline-face | face | shadow | Face used for the modeline status text | modeline/context-navigator-view-modeline.el |
- Minimal setup
(use-package context-navigator
:custom
(context-navigator-global-key "C-c n") ;; or nil if you prefer M-x
(context-navigator-autoload t)
(context-navigator-autosave t)
:config
(context-navigator-mode 1))
- Advanced setup (icons, indicators, widths, counters, auto‑project, language)
(use-package context-navigator
;; :straight (context-navigator :type git :host github :repo "11111000000/context-navigator")
:custom
;; Basics
(context-navigator-global-key "C-c n")
(context-navigator-autoload t)
(context-navigator-autosave t)
(context-navigator-view-width 36)
;; Sidebar & render
(context-navigator-controls-style 'icons)
(context-navigator-highlight-active-group t)
(context-navigator-openable-count-ttl 0.3)
(context-navigator-openable-soft-cap 120)
(context-navigator-openable-remote-mode 'lazy)
(context-navigator-render-indicator-style 'icons)
(context-navigator-render-show-path t)
;; Icons
(context-navigator-enable-icons t)
(context-navigator-icons-disable-on-remote t)
;; Project switching & persistence
(context-navigator-context-switch-interval 0.7)
(context-navigator-create-default-group-file t)
;; GPTel apply (optional deferred mode)
;; (context-navigator-gptel-require-visible-window t)
;; Language
(context-navigator-language 'auto)
;; Stability with sidebar
(context-navigator-protect-sidebar-windows t)
:config
(context-navigator-mode 1))
- Navigator never imports from GPTel. It only pushes when you ask (Push now) or when auto‑push is ON.
- On push, Navigator resets GPTel context and adds all enabled items (files, buffers, selections).
- Indicators (green/gray) show binary membership in GPTel next to items (when enabled).
- Selections may require a reset under certain GPTel APIs; Navigator handles this automatically.
- Background apply is batched, and can be deferred until a GPTel buffer is visible (see
context-navigator-gptel-require-visible-window
). - Remote files: adds warn/confirm where appropriate; GPTel add functions require readable files/buffers.
How to use:
- Toggle auto‑push in the header ([→]) or via transient (G).
- Press [⇪] Push now in the footer, or P in transient, for a manual reset + add.
- Clear GPTel via footer [⌦] or transient (C).
Minimize enabled context for the current task described in your org buffer:
- Where: org-mode only (appears as R “Occam filter (org)” in the transient).
- Source: active region if any; otherwise the whole org buffer.
- Payload: content of currently enabled items (files/buffers/selections) is included for the model to reason about.
- Safety:
- Warns and confirms when remote (TRAMP) content is present (configurable).
- Warns on large payloads before sending (rough token budget is shown in Stats).
- Parsing modes:
- flex (default): tries strict JSON first; if absent, accepts plain identifiers (keys/paths/names). Optional cautious fuzzy matching.
- json-only: require strict JSON; offers an automatic retry with stricter instruction on parse error.
- Apply flow:
- Preview counts before applying (enabled vs total); confirm or cancel.
- Applies by enabling only the returned items; auto-push to GPTel is respected when ON.
- Per-group Undo/Redo available via the header toolbar (↶/↷) if the result doesn’t look right.
Key options (defaults):
- context-navigator-razor-model: “deepseek-chat”
- context-navigator-razor-parse-mode: flex
- context-navigator-razor-flex-allow-fuzzy: nil
- context-navigator-razor-max-output-tokens: 256
- context-navigator-razor-timeout: 45
- context-navigator-razor-remote-include: t
- context-navigator-razor-large-bytes-threshold: 600000
- context-navigator-razor-budget-tokens-limit: 100000
- context-navigator-razor-preview: t
- context-navigator-undo-depth: 10
- Format v3, one file per group:
- Project:
<project>/.context/<group>.el
- Global:
~/.context/<group>.el
- Project:
state.el
tracks the current group and display names.- Async load with batching, spinner, and progress events.
- On unreadable/broken group file, the sidebar can auto‑open the groups list (configurable via
context-navigator-auto-open-groups-on-error
).
Tips:
- The first time you open a project/global context, a default group file can be auto‑created (see
context-navigator-create-default-group-file
). - Switching groups saves the previous group automatically and loads the new one asynchronously.
- Roots from
project.el
or projectile (if available). - “Interesting” buffers:
- File‑backed buffers
- gptel/gptel-aibo buffers (derived modes and gptel-aibo minor mode)
- Dired (and wdired) buffers
- Auto‑switch is throttled (see
context-navigator-context-switch-interval
) and sticky (keep last root instead of flickering to global). - Child frames (posframe/popups) and certain internal buffers (e.g., corfu) are ignored.
Manual project switch at any time: M-x context-navigator-switch-to-current-buffer-project
(also bound to transient “p”).
- “Open buffers” counter is remote‑aware:
- off — ignore remote files
- lazy — do not stat TRAMP paths; consider openable if no live buffer exists
- strict — verify existence with
file-exists-p
even over TRAMP (may be slow)
- Soft cap and TTL keep the counter responsive (see
context-navigator-openable-soft-cap
andcontext-navigator-openable-count-ttl
). - Mask/glob expansion skips TRAMP by default (enable via
context-navigator-mask-enable-remote
only if you need it).
- The menu/keys don’t work?
- Ensure
context-navigator-mode
is enabled and setcontext-navigator-global-key
(or callM-x context-navigator-transient
).
- Ensure
- Navigator doesn’t open?
- Try
M-x context-navigator-start
orM-x context-navigator-open
.
- Try
- Icons are missing?
- Install
all-the-icons
and runM-x all-the-icons-install-fonts
, then restart Emacs.
- Install
- GPTel is not installed?
- Navigator works fine without it. Push operations will no‑op with an informative message.
- Group load failed?
- The sidebar can auto‑open the groups list; from there you can delete or fix the group file.
- How do I save/load/unload?
- Save:
M-x context-navigator-context-save
. Load:M-x context-navigator-context-load
. Unload (switch to global):M-x context-navigator-context-unload
(also transient “X”).
- Save:
- How to manage groups?
- From the sidebar groups view: a (add), r (rename), c (duplicate), d (delete).
- How to clear GPTel or the group?
- Press C in the sidebar (or use transient “C”) to clear GPTel. Use “E” to clear the current group.
- Open/close all context buffers?
- Header [O]/[K], sidebar keys O/o and K.
Issues and pull requests are welcome. Please:
- Include clear reproduction steps and Emacs/version info in bug reports.
- Keep patches small and focused; prefer functional, side‑effect‑local changes.
- Update docstrings and this README when behavior or user‑facing options change.
MIT — see LICENSE.