Skip to content

codex()/claude() shell wrappers break under Claude Code's Bash tool — snapshot capture drops single-underscore helper names #2969

Description

@riskatcher

Summary

setup-helper/wrapper.sh in both examples/codex-memory-plugin/ and examples/claude-code-memory-plugin/ defines a public wrapper (codex() / claude()) that calls private helpers named with a single leading underscore (_openviking_codex_exec, _openviking_run, _openviking_dispatch, _openviking_define_wrappers, _openviking_codex_plugin_dir). When invoked from Claude Code's own Bash tool, this fails with zsh: command not found: _openviking_codex_exec (exit 127) — it works fine from a normal interactive terminal.

Root cause

Claude Code doesn't re-source .zshrc on every Bash tool call. At session start it snapshots the interactive shell's function definitions to a static file and replays that snapshot for every subsequent call (avoids re-running slow interactive init on each command). That snapshot step silently drops every function whose name starts with exactly one leading underscore — almost certainly to avoid dumping zsh's large completion-function namespace (_git, _npm, etc., which follow the same single-underscore convention). Double-underscore names (__foo) are preserved.

Since the public wrapper itself (codex/claude) has no leading underscore, it survives the snapshot and gets invoked — then immediately fails calling a helper that was silently dropped from the replayed shell state.

This isn't an edge case: an AI coding agent invoking codex/claude non-interactively via a Bash tool is a core usage path this plugin exists to support (injecting OPENVIKING_* credentials at launch).

Verified fix

Renaming every _openviking_* helper to __openviking_* (double leading underscore) makes them survive Claude Code's snapshot filter, with no other behavior change. Confirmed locally:

  • repo-wide grep shows no other file references these helper names by string (safe rename, no other call sites)
  • zsh -n is syntax-clean on both wrapper.sh files after the rename
  • a fresh zsh -c 'source wrapper.sh; codex --version' resolves the full renamed call chain and runs correctly

Happy to open a PR with the rename applied to both wrapper.sh files if that's useful — flagging as an issue first in case there's a preferred approach (e.g. avoiding shell-function state entirely for this kind of snapshot-replay environment).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions