hephaestus/docs/reference/heph-nvim.md
Erich Blume 7c9a734ebd
Some checks failed
Build / validate (pull_request) Failing after 2s
heph.nvim: task views — next/list/capture/attention/state/log (slice 11b)
Backend: enrich `list` to return titled RankedTask rows (title +
canonical_context_id, via a shared ranked_from_row with `next`), so the
Organizational view needs no N+1 node.get. TDD: query_surface test asserts
list rows carry title + context id.

Plugin:
- view.lua: Tactical `next` + Organizational `list` rendered scratch buffers;
  <CR> opens the row's canonical-context doc. Narrowed the node autocmd to
  heph://node/* so view buffers (heph://next, heph://list) don't trip it.
- task.lua: capture, set-attention, done/drop, skip, per-task log append, all
  resolving "the current task" from the buffer (a task node, or a context doc
  via its canonical-context backlink).
- picker.lua: vim.ui.select with Telescope auto-upgrade (headless-safe).
- command.lua: :Heph next/list/capture/attention/done/drop/skip/log/search.

e2e: capture→next→open context→add/check checklist→done; recurring
fresh-checklist (complete rolls forward in place, next occurrence all-unchecked
— the §4.4 hard requirement). 6 specs green via `mise run test-nvim`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 21:12:56 -07:00

4.2 KiB

title modified tags
heph.nvim 2026-06-01
reference
design

heph.nvim

The primary user surface (tech-spec §8): a Neovim plugin that replaces obsidian.nvim and is a thin client of the local hephd over its unix-socket JSON-RPC. Notes, journals, and tasks are edited as ordinary buffers; the daemon owns all storage and sync. Built in checkpointed slices on feature/v1-prototype; this card tracks the stable surface as it lands.

Architecture

heph.nvim/lua/heph/ modules, each small and single-purpose:

Module Responsibility
rpc libuv (vim.uv) unix-socket JSON-RPC client. A blocking call() is built over the async pipe by pumping the loop with vim.wait until the matching id returns. Demuxes responses by id; partial lines are buffered; JSON null decodes to Lua nil (luanil). A Session is one connection — the module keeps a default singleton and lets tests open isolated sessions.
node Buffer-backed nodes. A node is a buffer named heph://node/<id> with buftype=acwrite; BufReadCmd loads the body via node.get, BufWriteCmd saves the whole buffer via node.update.
link Parse the [[wiki-link]] under the cursor (mirroring extract.rs grammar) and follow it via node.resolve (exact, never fuzzy search). Unresolved links are allowed.
journal Open/create a dated journal node (idempotent — deterministic id).
daemon Locate / spawn / readiness-poll hephd (shared with the e2e harness).
config / init setup(opts), socket resolution, default keymaps.
command The :Heph <subcommand> dispatch + completion.

Surfaces never touch SQLite — every operation is a daemon RPC (tech-spec §3). The plugin is mode-agnostic: Tactical/Strategic/Organizational are plugin-side compositions of daemon primitives, not daemon concepts.

Daemon RPC dependencies

Beyond the existing methods (tech-spec §6), the plugin relies on node.resolve {title} → Node | null: an exact, owner-scoped, non-tombstoned alias-then-title match — the same mapping the store uses to materialize wiki links, so "follow link under cursor" jumps to the same node the stored link points at.

Commands (as of slice 11b)

Command Action
:Heph today / :Heph journal <YYYY-MM-DD> Open today's / a dated journal
:Heph follow (also <CR> in a node buffer) Follow the [[link]] under the cursor
:Heph open <id> Open a node buffer by id
:Heph search <query> Full-text search; pick a result to open
:Heph next [scope] Tactical "what is next?" view (<CR> opens a task's context)
:Heph list [attention] Organizational survey of the outstanding set
:Heph capture <title> Capture a committed task (pick attention)
:Heph attention [color] Set the current task's attention
:Heph done / :Heph drop / :Heph skip State change on the current task
:Heph log <text> Append a breadcrumb to the current task's log

"Current task" is resolved from the buffer: a task node, or a canonical-context doc whose owning task is followed via its canonical-context backlink. The next/list views render the titled rows the daemon returns (list enriched to carry titles + the context id, so no N+1 node.get). Pickers use built-in vim.ui.select, auto-upgrading to Telescope when installed.

Context-item promotion (:Heph promote) and the CI runner arrive in slice 11c.

Testing (tech-spec §9)

The headless e2e suite drives the plugin in nvim --headless against a real hephd over a temp socket, asserting both buffer contents and resulting DB state (via an isolated RPC session). It uses a self-contained busted-style runner (tests/e2e/runner.lua) — no external plugins, no network — so it is deterministic. mise run test-nvim builds the daemon and runs the suite against system-installed Neovim; a deliberately failing spec exits non-zero (no false-green). In CI the same suite runs inside a Dagger container that provides Neovim + the Rust toolchain (slice 11c).

  • tech-spec — §8 surface spec, §6 RPC API, §9 testing strategy
  • design — the mode model (Tactical/Strategic/Organizational) and rationale