Field Notes

How We Got VS Code to Use the Obsidian CLI

The real obstacle was not access to Obsidian. It was the mismatch between terminal assumptions, desktop app behavior, and sandbox boundaries.

AIObsidianVS Code

How We Got VS Code and Codex to Use the Obsidian CLI

Why This Post Exists

This exists because I needed an AI-powered, self-hosted knowledge management system. After hearing what others were doing with their “second brains,” I decided to try it myself.

That quickly turned into a more practical question: how do I make Visual Studio Code, a coding agent, and Obsidian work together in the same environment without constant friction?

At first, this looked like a simple tooling problem. We had Obsidian open. We had VS Code open. We had a coding agent working inside the shared workspace. The obvious next step was to let the agent use the Obsidian CLI the same way it would use any other terminal tool.

That assumption turned out to be wrong.

The good news is that we did get it working. The useful part of the story is not some clever trick. It is understanding what kind of tool Obsidian actually is and why the environment around it matters.

The first mistake: treating Obsidian like a normal CLI

After thinking I had Visual Studio Code, Obsidian, and the Obsidian CLI ready for this experiment, I asked Codex to see what it could do with the Obsidian CLI. As many of us are learning, this was not as simple as the hype suggested.

Our (Codex’s) first instinct was to try standard command-line habits:

  • obsidian --help
  • obsidian --version
  • obsidian --vault my-vault

Those went nowhere.

At first glance, it looked like the agent simply could not reach Obsidian from inside VS Code. That was not the real problem. The executable was there. The mental model was wrong.

On macOS, the obsidian command is tied to the desktop application. It is not a conventional Unix-style utility that just prints help, parses familiar flags, and exits. It expects to cooperate with the running app, its settings, and its own command syntax.

Once we stopped assuming “normal CLI,” the rest of the behavior made a lot more sense.

The second mistake: forgetting that the CLI must be enabled

Obsidian’s command interface is not just automatically available because the app is installed.

You have to enable the CLI feature inside Obsidian itself.

That matters because without that setting turned on, a coding agent can spend a lot of time exploring the wrong explanation. You can end up thinking the tool is missing, the path is broken, or the sandbox is the whole problem when the app is simply not exposing the interface you expected.

So the first practical checkpoint became very simple:

  • make sure the Obsidian CLI feature is enabled in Settings

The third mistake: using the wrong syntax

This was the turning point.

The human side of the partnership noticed that obsidian help worked in a normal terminal. That one detail mattered because it showed the tool was real and callable, but not in the way we first expected.

Obsidian’s CLI uses a command-first style:

obsidian <command> [options]

In our setup, that meant commands like these:

obsidian vault vault="my-vault"
obsidian files vault="my-vault"
obsidian search vault="my-vault" query="checklist"

That is why --help and other standard flag patterns led us in the wrong direction. The failure was not proof of no access. It was proof that we were speaking the wrong dialect.

Where VS Code and sandboxing complicated things

This is the part that made the debugging more interesting.

The coding agent was running from the shared workspace in VS Code, but it was still operating inside a sandboxed environment. That meant some commands did not behave the same way they did in the user’s own terminal, especially when the command tried to interact with a desktop app.

From the user’s terminal, obsidian help could work because it was running in the user’s normal macOS session with access to the already installed app and its live state.

From the agent’s environment, calling obsidian was more subtle:

  • the executable could be present
  • the app could still be reachable in some cases
  • but launch behavior and handoff behavior did not necessarily match the user’s shell

That distinction mattered a lot.

We were not dealing with a simple “works” versus “does not work” situation. We were dealing with two different execution environments touching the same desktop application under different constraints.

Once we understood that, the debugging got calmer. We stopped treating every failure as mysterious. Some failures were syntax problems. Some were app-state problems. Some were sandbox-boundary problems.

What actually helped

A few habits made the integration much more reliable.

Keep Obsidian running

Because the CLI is tied to the desktop application, having Obsidian already open reduced confusion. On macOS, that made command handoff more predictable.

Always specify the vault explicitly

This became one of our strongest rules:

obsidian search vault="my-vault" query="checklist"

Do not rely on whichever vault happens to be open. Hidden app state is fragile. Explicit vault targeting is much safer.

Verify the environment before assuming the problem

We learned to ask:

  • Is the CLI enabled?
  • Is Obsidian already running?
  • Are we using Obsidian’s syntax, not Unix flag syntax?
  • Is this failure about access, or about sandbox behavior?

That sounds small, but it saved a lot of wasted motion.

The real lesson

The important lesson was not “here is the magic command.”

The important lesson was that desktop-app CLIs are not always true peers of normal terminal tools, especially when you bring coding agents and sandboxed execution into the picture.

What looked like one integration problem was actually three smaller ones stacked together:

  • app configuration
  • command syntax
  • execution environment

Once we separated those, the path forward became clear.

We were able to use VS Code as the implementation environment, keep Obsidian as the thinking environment, and let the coding agent interact with Obsidian more intentionally instead of by guesswork.

That is the kind of progress I trust most: not just getting a tool to work once, but understanding why it failed the first few times.

And while we are just getting started down this journey with a second brain, we will continue to post about both our successes and our failures.