Skip to content

Hooks silently not loaded from a local directory marketplace; ZCode 0.16.5 Stop transcript is assistant-only so stock sync always fails #2

Description

@elijah7x

Environment: plugin 0.2.0, nmem 0.10.73, ZCode CLI 0.16.5 / App 3.10.0, macOS — two Macs with identical versions of both nmem and the plugin.

We spent a full day diagnosing why one Mac auto-synced ZCode sessions and the other silently synced nothing. Two independent failure modes found; documenting both so others (and the plugin) can short-circuit this.

1. Same plugin, different marketplace source → hooks loaded vs never loaded

  • Mac A installed via the GitHub marketplace source → plugin hooks load, sessions auto-sync. ✅
  • Mac B installed the same plugin 0.2.0 from a local directory marketplace (local clone registered as a directory-type source) → ZCode never loads the plugin's hooks. ❌

The only observable signal is in ZCode's startup log (~/.zcode/cli/log/zcode-<date>.jsonl, event bootstrap.app.startup.plugins.completed): hookCount: 0 on Mac B vs a positive count on Mac A. Nothing surfaces in the UI; nmem doctor shows everything green on both. Sessions just silently never sync.

The marketplace registration itself looks healthy on Mac B: plugin listed as enabled, cache populated, commands/skills resolvable.

Suggestions:

  • Make hooks from directory-source marketplaces load identically to GitHub-sourced ones — or fail loudly / document the limitation.
  • Add a doctor check "ZCode actually registered the plugin's hooks" (reading the same hookCount signal), so this failure mode is diagnosable without cross-machine diffing.

2. ZCode 0.16.5's Stop transcript contains only the last assistant message

ZCode 0.16.5's hook runner writes the Stop transcript as a single JSONL line with only the final assistant message:

{"message":{"content":[{"text":"","type":"text"}],"role":"assistant"}}

(see Hei() in zcode.cjs — JDr("assistant", e.responseText ?? e.responsePreview)).

nmem t sync --from zcode then rejects it with:

ZCode session needs at least one user and one assistant message

So on this ZCode build the stock Stop hook fires but the sync can never succeed — the error only appears in hook stderr.

Workaround we deployed (working reliably on 0.16.5): instead of copying transcript_path, the Stop hook exports the full user/assistant conversation for session_id straight from ~/.zcode/cli/db/db.sqlite (session/message/part schema is OpenCode-compatible), emits it in the same one-line-per-message format, and feeds that to t sync --from zcode --apply. Full conversation per turn, idempotent, and it also survives the assistant-only transcript limitation.

Longer-term options:

  • Have the hook script fall back to reading the ZCode sqlite store (like the workaround above), or
  • Have t sync --from zcode tolerate assistant-only transcripts by pulling the missing user turns via --session-id.

Footnote

Two more things that extended our debugging session, in case they help others:

  • The MCP server type must be http (not streamableHttp) in ~/.zcode/cli/config.json — wrong values are silently skipped (only a config.mcp_server.skipped warn in the same log file).
  • Hooks are registered when the ZCode process starts; editing config.json requires a full app restart for hooks (MCP reconnects per session and picks changes up immediately).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions