hephaestus/docs/reference/heph-nvim.md
Erich Blume b97c387252
Some checks failed
Build / validate (pull_request) Failing after 3s
heph.nvim: context-item promotion + Dagger headless-nvim CI (slice 11c)
Backend (TDD):
- task.promote {container_id, item_ref, attention?, project?}: mint a committed
  task from the item_ref-th `- [ ]` context item (1-based, document order via a
  new extract::context_item_lines) and rewrite that source line into a [[link]]
  to it. Unit + rpc_socket tests.
- resolve_id now excludes canonical-context docs, so [[Task Title]] resolves to
  the task, not its identically-titled context doc (deterministic; a general fix
  surfaced by promotion's ULID-tiebreak ambiguity).

Plugin: :Heph promote / promote_under_cursor (save-if-dirty → compute item index
with a code-fence-aware scanner mirroring extract.rs → task.promote → reload the
rewritten buffer). e2e spec (f): promote a context line, assert the new task in
next, the source line became a link, and the container backlinks the task.

CI via Dagger: a test_nvim function bakes a pinned, arch-detected Neovim
(v0.11.2 — Debian's is too old for vim.uv) onto rust:1-bookworm, builds hephd,
and runs the self-contained shim suite (cargo + target cache volumes);
build.yaml calls `dagger call test-nvim`. run.lua now fails on zero specs (no
false-green). Validated end-to-end: passing suite → exit 0, failing spec →
Dagger exit 1.

117 Rust tests + 7 nvim e2e specs green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 06:08:41 -07:00

4.9 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 11c)

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 promote [attention] Promote the - [ ] line under the cursor to a committed 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.

Promotion (:Heph promote) mints a committed task from the - [ ] line under the cursor (the daemon's task.promote, item_ref = the cursor item's 1-based index among context items, computed code-fence-aware to mirror extract.rs) and rewrites that line into a [[link]] to the new task. To keep that link unambiguous, wiki-link resolution excludes canonical-context docs, so [[Task Title]] resolves to the task, not its identically-titled context doc.

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; the runner also fails if it discovers zero specs). CI runs the same suite through the test-nvim Dagger function (.dagger/, invoked by build.yaml as dagger call test-nvim), which bakes a pinned, arch-detected Neovim onto a Rust image, builds hephd, and runs the suite — reproducible, and identical to the native mise run test-nvim path.

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