Make mise the dev entrypoint for the headless e2e suite, matching the repo's mise-tasks convention (auto-discovered, shows in `mise tasks`). Dev relies on system-installed nvim + rustc; CI will provide them via Dagger (slice 11c). The self-contained shim runner is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3.4 KiB
| title | modified | tags | ||
|---|---|---|---|---|
| heph.nvim | 2026-06-01 |
|
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 11a)
| Command | Action |
|---|---|
:Heph today |
Open today's journal |
:Heph journal <YYYY-MM-DD> |
Open 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 |
Task/agenda views (:Heph next/list/capture, set-attention, done/drop),
the per-task log, and context-item promotion arrive in slices 11b/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).