⏳ This skill is pending AI review.

Scores will appear once the review pipeline completes.

version unknown

vault-sync

@graphlit⭐ 2 stars

Use when a user wants an AI agent to install Vault Sync, mirror an existing Vault Git repository to local files, keep it refreshed, or consume an already-synced Vault with normal filesystem tools.

Choose how to use this skill

You do not need every option. Choose the path your AI client supports. The stable page stays the same; versioned files are immutable.

1. Native installer

This listing has no registered native installer command. Use the complete package or source fallback below, depending on what your client supports.

Do not guess an installer command or replace an existing version without reviewing the diff.

2. Complete package recommended

Download the ZIP when available. It includes SKILL.md plus the references, security notes and version metadata.

No complete ProSkills package is published for this listing yet.

3. Prompt-only

Copy the prompt above when the agent can read the stable page or when you want to adopt the workflow without installing a skill.

Need only the instruction file?

Download SKILL.md only if your client requires a single file. The complete ZIP is safer for a full installation because it preserves the references and release context.

No path installs or executes anything by itself. Your agent still needs access to the project files. Before updating, compare the installed version and review the diff.

—/10

// RATINGS

⭐GitHub Stars
⭐ 2 on GitHubGitHub ↗

New / niche

🟢ProSkills Score
—
📍

Not yet listed on ClawHub or SkillsMP

// README

Vault Sync

Vault Sync keeps a Vault Git repository synced to your computer.

A Vault is a Git repository of Markdown files: notes, source material, transcripts, summaries, observations, and other context exported from your app. Vault Sync keeps those files fresh locally so AI tools can read them without needing a live app connection.

Who It Helps

Personal knowledge Vaults can keep everyday context available to local AI tools:

  • students with lecture notes, readings, and research papers
  • researchers cross-referencing papers, citations, and notes
  • freelancers juggling client docs, project notes, and emails
  • homemakers organizing recipes, household docs, school info, and planning
  • job seekers tracking resumes, cover letters, postings, and interview prep
  • hobbyists and makers collecting tutorials, references, and project logs
  • writers working across drafts, research, notes, and source material

Team and business Vaults can keep operational context available locally:

  • engineering and product teams reviewing incident context and feature history
  • account executives preparing for calls and relationship updates
  • support teams researching incidents, escalations, and account history
  • leaders preparing for board meetings, partner syncs, or investor updates
  • customer success teams preparing QBRs and account reviews
  • deal teams and investors reviewing diligence material and portfolio context

What It Does

  • clones an existing Vault repository to your computer
  • pulls updates on demand
  • can install a recurring local pull schedule
  • reports sync status and local health
  • keeps the Vault ready for file-based AI tools

What It Does Not Do

  • does not create or manage your Vault
  • does not call back to the app that generated the Vault
  • does not search, chat, summarize, rank, or index
  • does not edit generated Vault files
  • does not push changes back to the Vault repository

Vault Sync is the mirror. Your AI tool is the reader.

Supported Platforms

Vault Sync currently supports:

  • macOS
  • Linux
  • WSL2 Ubuntu and similar WSL2 Linux distributions

Native Windows PowerShell and Command Prompt usage are not currently supported. If you use Windows, run Vault Sync inside WSL2 and keep the Vault under the WSL filesystem, such as ~/vaults/<name>, especially when your AI tool also runs in WSL2.

Agent-First Install

Vault Sync is designed so an AI agent can set up the local mirror with your approval. You provide the Vault repository URL from your app; the agent installs the small vault-sync script, clones the repository, and optionally configures a recurring pull schedule.

If your agent supports skill installation from GitHub, install the setup and usage skills:

npx skills add graphlit/vault-sync --skill vault-sync-setup
npx skills add graphlit/vault-sync --skill vault-sync-use

Then ask your agent:

Set up Vault Sync for my Vault at <your-vault-repo-url>.

For agents that support direct skill URLs, point them at:

https://raw.githubusercontent.com/graphlit/vault-sync/main/skill.md

App-hosted skill entrypoints can also be served at:

https://www.zine.ai/skill.md
https://www.dossium.ai/skill.md

Codex CLI 0.121.0 or newer can also consume this repository as a plugin marketplace:

codex plugin marketplace add graphlit/vault-sync

After install, Codex refers to the marketplace by the name in this repo's metadata:

codex plugin marketplace upgrade graphlit-vault-sync
codex plugin marketplace remove graphlit-vault-sync

Install

Clone this repository and install the script somewhere on your PATH:

git clone https://github.com/graphlit/vault-sync
cd vault-sync
install -m 0755 bin/vault-sync ~/.local/bin/vault-sync

If ~/.local/bin is not on your PATH, either add it or run the script directly from this checkout:

bash bin/vault-sync status ~/vaults/my-vault

Quick Start

Use the Vault repository URL from your app:

vault-sync init <your-vault-repo-url> ~/vaults/my-vault
vault-sync pull ~/vaults/my-vault
vault-sync status ~/vaults/my-vault

Then point your AI tool at the local folder:

~/vaults/my-vault

Ask your tool to inspect the Markdown files directly. For example, in Claude Code, Codex, OpenClaw, Cursor, or VS Code:

Use the local Vault in ~/vaults/my-vault to answer this. Start by reading README.md, then search the Markdown files.

You can also search the files yourself:

rg -n "your search terms" ~/vaults/my-vault

Commands

vault-sync init <repo-url> [path]
vault-sync pull [path]
vault-sync status [path]
vault-sync schedule install [path] --every 5m
vault-sync schedule remove [path]
vault-sync doctor [path]

The command surface is intentionally small. Search and reading are handled by your AI tool's normal file access.

Working With AI Tools

Vault Sync works well with file-aware tools such as:

  • Claude Code
  • Codex
  • OpenClaw
  • Cursor
  • VS Code

Suggested prompt:

The Vault is a local folder of Markdown files. Read README.md first. Ignore hidden control folders like .git, .zine, .dossium, .graphlit, .claude, and .codex. Use normal file tools to search and read the Markdown files.

Optional: Search Companion With QMD

QMD is a local search companion for folders full of Markdown. Vault Sync and QMD fit together well:

  • Vault Sync keeps the Vault Git repository current on disk.
  • QMD can make the synced Markdown easier to search.
  • Your agent can still open the actual files whenever it needs the full source.

The workflow is simple: sync the Vault first, then let QMD search the local folder. Install QMD separately, then add the local Vault folder:

npm install -g @tobilu/qmd

vault-sync pull ~/vaults/my-vault
qmd collection add ~/vaults/my-vault --name my-vault --mask "**/*.md"
qmd context add qmd://my-vault "Local Vault synced by Vault Sync"
qmd embed

Then agents can use QMD as an optional search helper:

qmd query "customer escalation patterns" -c my-vault --json -n 10
qmd get "path/from/result.md" --full

QMD is not required. Vault Sync does not install, configure, or depend on QMD; it just keeps the local files fresh so tools like QMD can use them.

Keeping It Fresh

Pull updates manually:

vault-sync pull ~/vaults/my-vault

Or install a recurring pull schedule:

vault-sync schedule install ~/vaults/my-vault --every 5m

Remove the schedule later:

vault-sync schedule remove ~/vaults/my-vault

Security

  • plain Bash script
  • no opaque binary
  • no credentials stored by Vault Sync
  • Git authentication stays in your existing Git or GitHub setup
  • scheduled jobs only run vault-sync pull <path>
  • local Vault files are not uploaded by this tool

Troubleshooting

Run:

vault-sync doctor ~/vaults/my-vault

This checks for Git, repository health, local changes, remote reachability, optional rg, and scheduler state.

Agent Install Notes

See:

These examples are intentionally focused on agent setup and consumption. Vault creation and management stay in the app that generated the Vault.

Development

Run the smoke test with:

bash tests/smoke.sh

The test creates a temporary local Git repository and does not touch your real Vaults.

// HOW IT'S BUILT

// FILES

19 files shipped with this skill. Inline text is the catalog copy. The upstream link is the source repository.

  • plugins/vault-sync/skills/vault-sync-setup/SKILL.md2.0 KBceeef92f4235upstream ↗
    ---
    name: vault-sync-setup
    description: Use when the user wants to install Vault Sync, connect an existing Vault Git repository to a local folder, refresh it, configure a recurring pull schedule, or make a local Vault available to an AI agent through filesystem files.
    ---
    
    # Vault Sync Setup
    
    Vault Sync mirrors an existing Vault Git repository to local files. It does not create Vaults, manage replicas, call app APIs, search, query, summarize, rank, index, or push changes.
    
    ## Workflow
    
    1. Confirm the environment is macOS, Linux, or WSL2. For Windows users, recommend WSL2 and keep the Vault under the WSL filesystem.
    2. Check for `bash` and `git`. `rg` is optional but useful for later consumption.
    3. Install `vault-sync` if it is not already on `PATH`. Prefer the bundled script:
    
    ```bash
    bash skills/vault-sync-setup/scripts/install-vault-sync.sh
    ```
    
    If the bundled script is unavailable, install from GitHub:
    
    ```bash
    mkdir -p ~/.local/bin
    curl -fsSL https://raw.githubusercontent.com/graphlit/vault-sync/main/bin/vault-sync -o ~/.local/bin/vault-sync
    chmod +x ~/.local/bin/vault-sync
    ```
    
    4. Ask for the Vault Git repository URL and preferred local folder if missing. Use `~/vaults/<repo-name>` as the default.
    5. Do not infer the local Vault path from the current working directory, app name, or repository owner. Do not invent hidden app folders such as `~/.zine/vault`, `~/.dossium/vault`, or `~/.graphlit/vault`.
    6. Initialize and verify:
    
    ```bash
    vault-sync init <vault-repo-url> <path>
    vault-sync pull <path>
    vault-sync doctor <path>
    ```
    
    7. Ask before installing a recurring schedule. If approved:
    
    ```bash
    vault-sync schedule install <path> --every 5m
    ```
    
    ## Agent Behavior
    
    - Treat the Vault as generated, read-only context.
    - Do not edit Vault files unless the user explicitly asks to modify local copies.
    - Do not use `vault-sync` as a search or read API. After setup, use normal filesystem tools.
    - If Git authentication fails, let the user complete their normal Git or GitHub CLI authentication flow.
    
  • plugins/vault-sync/skills/vault-sync-use/SKILL.md1.4 KB48d5b49122f9upstream ↗
    ---
    name: vault-sync-use
    description: Use when the user wants an AI agent to answer questions or perform research from an already-synced Vault folder using local Markdown files and normal filesystem tools.
    ---
    
    # Vault Sync Use
    
    Use an already-synced Vault as local, read-only context. Vault Sync provides files; the agent does the reading and reasoning.
    
    ## Workflow
    
    1. If `vault-sync` is available and the user has not asked to avoid updates, refresh the Vault:
    
    ```bash
    vault-sync pull <path>
    ```
    
    2. Read `<path>/README.md` first to learn the Vault source and conventions.
    3. Ignore hidden control folders: `.git`, `.zine`, `.dossium`, `.graphlit`, `.claude`, and `.codex`.
    4. Search and read Markdown directly with normal filesystem tools:
    
    ```bash
    rg -n "<terms>" <path>
    ls <path>
    sed -n '1,160p' <file>
    ```
    
    5. Cite local file paths in responses when useful.
    
    ## Boundaries
    
    - Do not call app APIs for Vault consumption.
    - Do not use `vault-sync` for search, query, read, summarize, rank, or index.
    - Do not edit generated Vault files unless the user explicitly asks for local modifications.
    - If QMD is installed, it can be an optional local search helper. Add the Vault folder with `qmd collection add <path> --name <name> --mask "**/*.md"`, add context with `qmd context add qmd://<name> "Local Vault synced by Vault Sync"`, then run `qmd embed`. Use QMD to find likely files and local file reads for the full source. Do not require QMD.
    
  • skill.md2.3 KB22896e837a5bupstream ↗
    ---
    name: vault-sync
    description: Use when a user wants an AI agent to install Vault Sync, mirror an existing Vault Git repository to local files, keep it refreshed, or consume an already-synced Vault with normal filesystem tools.
    ---
    
    # Vault Sync
    
    Vault Sync mirrors an existing Vault Git repository onto the user's local filesystem. Use it only for file sync and local readiness. Do not use it for search, query, chat, indexing, Vault creation, or Vault management.
    
    ## When Setting Up
    
    1. Confirm the environment is macOS, Linux, or WSL2. Native Windows PowerShell and Command Prompt are out of scope.
    2. Check for `bash` and `git`. `rg` is optional but useful after sync.
    3. Install `vault-sync` if it is not already on `PATH`:
    
    ```bash
    mkdir -p ~/.local/bin
    curl -fsSL https://raw.githubusercontent.com/graphlit/vault-sync/main/bin/vault-sync -o ~/.local/bin/vault-sync
    chmod +x ~/.local/bin/vault-sync
    ```
    
    4. Ask for the Vault Git repository URL and local folder if the user did not provide them. Use `~/vaults/<repo-name>` as the default.
    5. Do not infer the local Vault path from the current working directory, app name, or repository owner. Do not invent hidden app folders such as `~/.zine/vault`, `~/.dossium/vault`, or `~/.graphlit/vault`.
    6. Run:
    
    ```bash
    vault-sync init <vault-repo-url> <path>
    vault-sync pull <path>
    vault-sync doctor <path>
    ```
    
    7. If the user wants recurring refreshes, install a pull schedule:
    
    ```bash
    vault-sync schedule install <path> --every 5m
    ```
    
    ## When Using A Synced Vault
    
    1. Refresh first when practical:
    
    ```bash
    vault-sync pull <path>
    ```
    
    2. Read `<path>/README.md` first.
    3. Ignore hidden control folders such as `.git`, `.zine`, `.dossium`, `.graphlit`, `.claude`, and `.codex`.
    4. Use ordinary filesystem tools: `ls`, `rg`, `sed`, `cat`, and native file reads.
    5. Treat the Vault as read-only unless the user explicitly asks to edit local files.
    
    ## Optional QMD Search Companion
    
    If QMD is installed and the user wants a stronger local search helper, add the synced Vault folder as a QMD collection:
    
    ```bash
    qmd collection add <path> --name <name> --mask "**/*.md"
    qmd context add qmd://<name> "Local Vault synced by Vault Sync"
    qmd embed
    ```
    
    Use QMD to find likely files; use file reads for the full source.
    
    Vault Sync is the mirror. The agent is the reader.
    
  • skills/vault-sync-setup/SKILL.md2.0 KBceeef92f4235upstream ↗
    ---
    name: vault-sync-setup
    description: Use when the user wants to install Vault Sync, connect an existing Vault Git repository to a local folder, refresh it, configure a recurring pull schedule, or make a local Vault available to an AI agent through filesystem files.
    ---
    
    # Vault Sync Setup
    
    Vault Sync mirrors an existing Vault Git repository to local files. It does not create Vaults, manage replicas, call app APIs, search, query, summarize, rank, index, or push changes.
    
    ## Workflow
    
    1. Confirm the environment is macOS, Linux, or WSL2. For Windows users, recommend WSL2 and keep the Vault under the WSL filesystem.
    2. Check for `bash` and `git`. `rg` is optional but useful for later consumption.
    3. Install `vault-sync` if it is not already on `PATH`. Prefer the bundled script:
    
    ```bash
    bash skills/vault-sync-setup/scripts/install-vault-sync.sh
    ```
    
    If the bundled script is unavailable, install from GitHub:
    
    ```bash
    mkdir -p ~/.local/bin
    curl -fsSL https://raw.githubusercontent.com/graphlit/vault-sync/main/bin/vault-sync -o ~/.local/bin/vault-sync
    chmod +x ~/.local/bin/vault-sync
    ```
    
    4. Ask for the Vault Git repository URL and preferred local folder if missing. Use `~/vaults/<repo-name>` as the default.
    5. Do not infer the local Vault path from the current working directory, app name, or repository owner. Do not invent hidden app folders such as `~/.zine/vault`, `~/.dossium/vault`, or `~/.graphlit/vault`.
    6. Initialize and verify:
    
    ```bash
    vault-sync init <vault-repo-url> <path>
    vault-sync pull <path>
    vault-sync doctor <path>
    ```
    
    7. Ask before installing a recurring schedule. If approved:
    
    ```bash
    vault-sync schedule install <path> --every 5m
    ```
    
    ## Agent Behavior
    
    - Treat the Vault as generated, read-only context.
    - Do not edit Vault files unless the user explicitly asks to modify local copies.
    - Do not use `vault-sync` as a search or read API. After setup, use normal filesystem tools.
    - If Git authentication fails, let the user complete their normal Git or GitHub CLI authentication flow.
    
  • skills/vault-sync-use/SKILL.md1.4 KB48d5b49122f9upstream ↗
    ---
    name: vault-sync-use
    description: Use when the user wants an AI agent to answer questions or perform research from an already-synced Vault folder using local Markdown files and normal filesystem tools.
    ---
    
    # Vault Sync Use
    
    Use an already-synced Vault as local, read-only context. Vault Sync provides files; the agent does the reading and reasoning.
    
    ## Workflow
    
    1. If `vault-sync` is available and the user has not asked to avoid updates, refresh the Vault:
    
    ```bash
    vault-sync pull <path>
    ```
    
    2. Read `<path>/README.md` first to learn the Vault source and conventions.
    3. Ignore hidden control folders: `.git`, `.zine`, `.dossium`, `.graphlit`, `.claude`, and `.codex`.
    4. Search and read Markdown directly with normal filesystem tools:
    
    ```bash
    rg -n "<terms>" <path>
    ls <path>
    sed -n '1,160p' <file>
    ```
    
    5. Cite local file paths in responses when useful.
    
    ## Boundaries
    
    - Do not call app APIs for Vault consumption.
    - Do not use `vault-sync` for search, query, read, summarize, rank, or index.
    - Do not edit generated Vault files unless the user explicitly asks for local modifications.
    - If QMD is installed, it can be an optional local search helper. Add the Vault folder with `qmd collection add <path> --name <name> --mask "**/*.md"`, add context with `qmd context add qmd://<name> "Local Vault synced by Vault Sync"`, then run `qmd embed`. Use QMD to find likely files and local file reads for the full source. Do not require QMD.
    
  • README.md7.4 KB41a3ffc0aac7upstream ↗
    # Vault Sync
    
    Vault Sync keeps a Vault Git repository synced to your computer.
    
    A Vault is a Git repository of Markdown files: notes, source material, transcripts, summaries, observations, and other context exported from your app. Vault Sync keeps those files fresh locally so AI tools can read them without needing a live app connection.
    
    ## Who It Helps
    
    Personal knowledge Vaults can keep everyday context available to local AI tools:
    
    - students with lecture notes, readings, and research papers
    - researchers cross-referencing papers, citations, and notes
    - freelancers juggling client docs, project notes, and emails
    - homemakers organizing recipes, household docs, school info, and planning
    - job seekers tracking resumes, cover letters, postings, and interview prep
    - hobbyists and makers collecting tutorials, references, and project logs
    - writers working across drafts, research, notes, and source material
    
    Team and business Vaults can keep operational context available locally:
    
    - engineering and product teams reviewing incident context and feature history
    - account executives preparing for calls and relationship updates
    - support teams researching incidents, escalations, and account history
    - leaders preparing for board meetings, partner syncs, or investor updates
    - customer success teams preparing QBRs and account reviews
    - deal teams and investors reviewing diligence material and portfolio context
    
    ## What It Does
    
    - clones an existing Vault repository to your computer
    - pulls updates on demand
    - can install a recurring local pull schedule
    - reports sync status and local health
    - keeps the Vault ready for file-based AI tools
    
    ## What It Does Not Do
    
    - does not create or manage your Vault
    - does not call back to the app that generated the Vault
    - does not search, chat, summarize, rank, or index
    - does not edit generated Vault files
    - does not push changes back to the Vault repository
    
    Vault Sync is the mirror. Your AI tool is the reader.
    
    ## Supported Platforms
    
    Vault Sync currently supports:
    
    - macOS
    - Linux
    - WSL2 Ubuntu and similar WSL2 Linux distributions
    
    Native Windows PowerShell and Command Prompt usage are not currently supported. If you use Windows, run Vault Sync inside WSL2 and keep the Vault under the WSL filesystem, such as `~/vaults/<name>`, especially when your AI tool also runs in WSL2.
    
    ## Agent-First Install
    
    Vault Sync is designed so an AI agent can set up the local mirror with your approval. You provide the Vault repository URL from your app; the agent installs the small `vault-sync` script, clones the repository, and optionally configures a recurring pull schedule.
    
    If your agent supports skill installation from GitHub, install the setup and usage skills:
    
    ```bash
    npx skills add graphlit/vault-sync --skill vault-sync-setup
    npx skills add graphlit/vault-sync --skill vault-sync-use
    ```
    
    Then ask your agent:
    
    ```text
    Set up Vault Sync for my Vault at <your-vault-repo-url>.
    ```
    
    For agents that support direct skill URLs, point them at:
    
    ```text
    https://raw.githubusercontent.com/graphlit/vault-sync/main/skill.md
    ```
    
    App-hosted skill entrypoints can also be served at:
    
    ```text
    https://www.zine.ai/skill.md
    https://www.dossium.ai/skill.md
    ```
    
    Codex CLI `0.121.0` or newer can also consume this repository as a plugin marketplace:
    
    ```bash
    codex plugin marketplace add graphlit/vault-sync
    ```
    
    After install, Codex refers to the marketplace by the name in this repo's metadata:
    
    ```bash
    codex plugin marketplace upgrade graphlit-vault-sync
    codex plugin marketplace remove graphlit-vault-sync
    ```
    
    ## Install
    
    Clone this repository and install the script somewhere on your `PATH`:
    
    ```bash
    git clone https://github.com/graphlit/vault-sync
    cd vault-sync
    install -m 0755 bin/vault-sync ~/.local/bin/vault-sync
    ```
    
    If `~/.local/bin` is not on your `PATH`, either add it or run the script directly from this checkout:
    
    ```bash
    bash bin/vault-sync status ~/vaults/my-vault
    ```
    
    ## Quick Start
    
    Use the Vault repository URL from your app:
    
    ```bash
    vault-sync init <your-vault-repo-url> ~/vaults/my-vault
    vault-sync pull ~/vaults/my-vault
    vault-sync status ~/vaults/my-vault
    ```
    
    Then point your AI tool at the local folder:
    
    ```text
    ~/vaults/my-vault
    ```
    
    Ask your tool to inspect the Markdown files directly. For example, in Claude Code, Codex, OpenClaw, Cursor, or VS Code:
    
    ```text
    Use the local Vault in ~/vaults/my-vault to answer this. Start by reading README.md, then search the Markdown files.
    ```
    
    You can also search the files yourself:
    
    ```bash
    rg -n "your search terms" ~/vaults/my-vault
    ```
    
    ## Commands
    
    ```bash
    vault-sync init <repo-url> [path]
    vault-sync pull [path]
    vault-sync status [path]
    vault-sync schedule install [path] --every 5m
    vault-sync schedule remove [path]
    vault-sync doctor [path]
    ```
    
    The command surface is intentionally small. Search and reading are handled by your AI tool's normal file access.
    
    ## Working With AI Tools
    
    Vault Sync works well with file-aware tools such as:
    
    - Claude Code
    - Codex
    - OpenClaw
    - Cursor
    - VS Code
    
    Suggested prompt:
    
    ```text
    The Vault is a local folder of Markdown files. Read README.md first. Ignore hidden control folders like .git, .zine, .dossium, .graphlit, .claude, and .codex. Use normal file tools to search and read the Markdown files.
    ```
    
    ## Optional: Search Companion With QMD
    
    [QMD](https://github.com/tobi/qmd) is a local search companion for folders full of Markdown. Vault Sync and QMD fit together well:
    
    - Vault Sync keeps the Vault Git repository current on disk.
    - QMD can make the synced Markdown easier to search.
    - Your agent can still open the actual files whenever it needs the full source.
    
    The workflow is simple: sync the Vault first, then let QMD search the local folder. Install QMD separately, then add the local Vault folder:
    
    ```bash
    npm install -g @tobilu/qmd
    
    vault-sync pull ~/vaults/my-vault
    qmd collection add ~/vaults/my-vault --name my-vault --mask "**/*.md"
    qmd context add qmd://my-vault "Local Vault synced by Vault Sync"
    qmd embed
    ```
    
    Then agents can use QMD as an optional search helper:
    
    ```bash
    qmd query "customer escalation patterns" -c my-vault --json -n 10
    qmd get "path/from/result.md" --full
    ```
    
    QMD is not required. Vault Sync does not install, configure, or depend on QMD; it just keeps the local files fresh so tools like QMD can use them.
    
    ## Keeping It Fresh
    
    Pull updates manually:
    
    ```bash
    vault-sync pull ~/vaults/my-vault
    ```
    
    Or install a recurring pull schedule:
    
    ```bash
    vault-sync schedule install ~/vaults/my-vault --every 5m
    ```
    
    Remove the schedule later:
    
    ```bash
    vault-sync schedule remove ~/vaults/my-vault
    ```
    
    ## Security
    
    - plain Bash script
    - no opaque binary
    - no credentials stored by Vault Sync
    - Git authentication stays in your existing Git or GitHub setup
    - scheduled jobs only run `vault-sync pull <path>`
    - local Vault files are not uploaded by this tool
    
    ## Troubleshooting
    
    Run:
    
    ```bash
    vault-sync doctor ~/vaults/my-vault
    ```
    
    This checks for Git, repository health, local changes, remote reachability, optional `rg`, and scheduler state.
    
    ## Agent Install Notes
    
    See:
    
    - [Agent Install Guide](docs/agent-install-guide.md)
    - [Claude Code](examples/install-claude-code.md)
    - [Codex](examples/install-codex.md)
    - [OpenClaw](examples/install-openclaw.md)
    
    These examples are intentionally focused on agent setup and consumption. Vault creation and management stay in the app that generated the Vault.
    
    ## Development
    
    Run the smoke test with:
    
    ```bash
    bash tests/smoke.sh
    ```
    
    The test creates a temporary local Git repository and does not touch your real Vaults.
    
  • .agents/plugins/marketplace.json379 Bed3accd8f137upstream ↗
    {
      "name": "graphlit-vault-sync",
      "interface": {
        "displayName": "Vault Sync"
      },
      "plugins": [
        {
          "name": "vault-sync",
          "source": {
            "source": "local",
            "path": "./plugins/vault-sync"
          },
          "policy": {
            "installation": "AVAILABLE",
            "authentication": "ON_INSTALL"
          },
          "category": "Productivity"
        }
      ]
    }
    
  • bin/vault-sync17 KB3828acb07675upstream ↗
    #!/usr/bin/env bash
    set -euo pipefail
    
    VERSION="0.1.0"
    APP_NAME="vault-sync"
    CONFIG_DIR="${VAULT_SYNC_CONFIG_DIR:-$HOME/.config/vault-sync}"
    STATE_DIR="$CONFIG_DIR/vaults"
    LOCK_DIR="$CONFIG_DIR/locks"
    SCHEDULE_DIR="$CONFIG_DIR/schedules"
    LOG_DIR="${VAULT_SYNC_LOG_DIR:-$CONFIG_DIR/logs}"
    ACTIVE_LOCK=""
    
    die() {
      printf 'vault-sync: %s\n' "$*" >&2
      exit 1
    }
    
    note() {
      printf '%s\n' "$*"
    }
    
    usage() {
      cat <<'EOF'
    vault-sync keeps an existing Vault Git repository mirrored onto the local filesystem.
    
    Usage:
      vault-sync init <repo-url> [path]
      vault-sync pull [path]
      vault-sync status [path] [--json]
      vault-sync schedule install [path] [--every 5m]
      vault-sync schedule remove [path]
      vault-sync doctor [path]
      vault-sync version
    
    Vault Sync mirrors files only. It does not search, query, read, summarize, rank,
    index, call Graphlit APIs, create Vaults, or push changes.
    EOF
    }
    
    ensure_dirs() {
      mkdir -p "$STATE_DIR" "$LOCK_DIR" "$SCHEDULE_DIR" "$LOG_DIR"
    }
    
    require_command() {
      command -v "$1" >/dev/null 2>&1 || die "Required command [$1] was not found."
    }
    
    expand_path() {
      case "${1:-}" in
        "~") printf '%s\n' "$HOME" ;;
        "~/"*) printf '%s/%s\n' "$HOME" "${1#~/}" ;;
        "") printf '%s\n' "" ;;
        *) printf '%s\n' "$1" ;;
      esac
    }
    
    absolute_path() {
      local raw parent base
      raw="$(expand_path "$1")"
      parent="$(dirname "$raw")"
      base="$(basename "$raw")"
      mkdir -p "$parent"
      parent="$(cd "$parent" && pwd -P)"
      printf '%s/%s\n' "$parent" "$base"
    }
    
    script_path() {
      local source_dir
      source_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
      printf '%s/%s\n' "$source_dir" "$(basename "${BASH_SOURCE[0]}")"
    }
    
    repo_name_from_url() {
      local url name
      url="${1%/}"
      name="${url##*/}"
      name="${name%.git}"
      [[ -n "$name" ]] || die "Could not infer a repository name from [$1]."
      printf '%s\n' "$name"
    }
    
    default_vault_path() {
      printf '%s/Vaults/%s\n' "$HOME" "$(repo_name_from_url "$1")"
    }
    
    state_id_for_path() {
      local path checksum base
      path="$1"
      checksum="$(printf '%s' "$path" | cksum | awk '{print $1}')"
      base="$(basename "$path" | tr -c 'A-Za-z0-9._-' '_')"
      printf '%s-%s\n' "$checksum" "$base"
    }
    
    state_file_for_path() {
      printf '%s/%s.env\n' "$STATE_DIR" "$(state_id_for_path "$1")"
    }
    
    state_get() {
      local path key file
      path="$1"
      key="$2"
      file="$(state_file_for_path "$path")"
      [[ -f "$file" ]] || return 0
      awk -F= -v key="$key" '$1 == key { sub(/^[^=]*=/, ""); print; exit }' "$file"
    }
    
    state_set() {
      local path key value file temp
      path="$1"
      key="$2"
      value="$3"
      ensure_dirs
      file="$(state_file_for_path "$path")"
      temp="$file.tmp.$$"
      if [[ -f "$file" ]]; then
        awk -F= -v key="$key" '$1 != key { print }' "$file" >"$temp"
      else
        : >"$temp"
      fi
      printf '%s=%s\n' "$key" "$value" >>"$temp"
      mv "$temp" "$file"
    }
    
    state_paths() {
      ensure_dirs
      find "$STATE_DIR" -type f -name '*.env' -print 2>/dev/null | while IFS= read -r file; do
        awk -F= '$1 == "path" { sub(/^[^=]*=/, ""); print; exit }' "$file"
      done
    }
    
    normalize_remote() {
      local remote
      remote="${1%/}"
      remote="${remote%.git}"
      printf '%s\n' "$remote"
    }
    
    remote_matches() {
      [[ "$(normalize_remote "$1")" == "$(normalize_remote "$2")" ]]
    }
    
    require_git_repo() {
      local path="$1"
      [[ -d "$path/.git" ]] || die "Path [$path] is not a Git repository."
    }
    
    worktree_dirty() {
      local path="$1"
      [[ -n "$(git -C "$path" status --porcelain)" ]]
    }
    
    markdown_count() {
      local path="$1"
      find "$path" -type f -name '*.md' \
        ! -path '*/.git/*' \
        ! -path '*/.zine/*' \
        ! -path '*/.dossium/*' \
        ! -path '*/.graphlit/*' \
        2>/dev/null | wc -l | tr -d ' '
    }
    
    resolve_vault_path() {
      local provided paths count path_line
      provided="${1:-}"
      if [[ -n "$provided" ]]; then
        absolute_path "$provided"
        return
      fi
    
      if [[ -d ".git" ]]; then
        pwd -P
        return
      fi
    
      paths=()
      while IFS= read -r path_line; do
        paths+=("$path_line")
      done < <(state_paths)
    
      count="${#paths[@]}"
      if [[ "$count" -eq 1 ]]; then
        printf '%s\n' "${paths[0]}"
        return
      fi
    
      if [[ "$count" -gt 1 ]]; then
        die "Multiple Vaults are configured. Pass a path explicitly."
      fi
    
      die "No Vault path was provided and no configured Vault was found."
    }
    
    json_escape() {
      local value="$1"
      value="${value//\\/\\\\}"
      value="${value//\"/\\\"}"
      value="${value//$'\n'/\\n}"
      value="${value//$'\r'/\\r}"
      printf '%s\n' "$value"
    }
    
    interval_to_seconds() {
      local value number unit
      value="${1:-5m}"
      if [[ "$value" =~ ^([0-9]+)([smhd]?)$ ]]; then
        number="${BASH_REMATCH[1]}"
        unit="${BASH_REMATCH[2]:-s}"
        case "$unit" in
          s) printf '%s\n' "$number" ;;
          m) printf '%s\n' "$((number * 60))" ;;
          h) printf '%s\n' "$((number * 3600))" ;;
          d) printf '%s\n' "$((number * 86400))" ;;
          *) die "Unsupported interval [$value]." ;;
        esac
      else
        die "Unsupported interval [$value]. Use values such as [5m], [30s], or [1h]."
      fi
    }
    
    interval_to_cron_minutes() {
      local seconds="$1"
      if (( seconds < 60 )); then
        die "Cron fallback requires an interval of at least 1 minute."
      fi
      if (( seconds % 60 != 0 )); then
        die "Cron fallback requires a whole-minute interval."
      fi
      if (( seconds > 3540 )); then
        die "Cron fallback supports intervals up to 59 minutes."
      fi
      printf '%s\n' "$((seconds / 60))"
    }
    
    schedule_id_for_path() {
      printf 'vault-sync-%s\n' "$(state_id_for_path "$1")"
    }
    
    make_schedule_wrapper() {
      local path interval_seconds id wrapper script jitter log script_arg path_arg log_arg
      path="$1"
      interval_seconds="$2"
      id="$(schedule_id_for_path "$path")"
      wrapper="$SCHEDULE_DIR/$id.sh"
      script="$(script_path)"
      jitter="$(( $(printf '%s' "$path" | cksum | awk '{print $1}') % 30 ))"
      log="$LOG_DIR/$id.log"
      printf -v script_arg '%q' "$script"
      printf -v path_arg '%q' "$path"
      printf -v log_arg '%q' "$log"
    
      ensure_dirs
      cat >"$wrapper" <<EOF
    #!/usr/bin/env bash
    set -euo pipefail
    sleep "$jitter"
    exec $script_arg pull $path_arg >>$log_arg 2>&1
    EOF
      chmod +x "$wrapper"
      note "$wrapper"
    }
    
    install_launchd_schedule() {
      local path interval_seconds id wrapper plist label
      path="$1"
      interval_seconds="$2"
      id="$(schedule_id_for_path "$path")"
      wrapper="$(make_schedule_wrapper "$path" "$interval_seconds")"
      label="com.graphlit.$id"
      plist="$HOME/Library/LaunchAgents/$label.plist"
      mkdir -p "$HOME/Library/LaunchAgents"
    
      cat >"$plist" <<EOF
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
      <key>Label</key>
      <string>$label</string>
      <key>ProgramArguments</key>
      <array>
        <string>/bin/bash</string>
        <string>$wrapper</string>
      </array>
      <key>StartInterval</key>
      <integer>$interval_seconds</integer>
      <key>RunAtLoad</key>
      <true/>
    </dict>
    </plist>
    EOF
    
      launchctl unload "$plist" >/dev/null 2>&1 || true
      launchctl load "$plist"
      state_set "$path" scheduler "launchd"
      state_set "$path" scheduler_id "$id"
      note "Installed launchd schedule [$label] for [$path]."
    }
    
    systemd_user_available() {
      command -v systemctl >/dev/null 2>&1 && systemctl --user status >/dev/null 2>&1
    }
    
    install_systemd_schedule() {
      local path interval_seconds id wrapper unit timer unit_dir
      path="$1"
      interval_seconds="$2"
      id="$(schedule_id_for_path "$path")"
      wrapper="$(make_schedule_wrapper "$path" "$interval_seconds")"
      unit_dir="$HOME/.config/systemd/user"
      unit="$unit_dir/$id.service"
      timer="$unit_dir/$id.timer"
      mkdir -p "$unit_dir"
    
      cat >"$unit" <<EOF
    [Unit]
    Description=Vault Sync pull for $path
    
    [Service]
    Type=oneshot
    ExecStart=/bin/bash $wrapper
    EOF
    
      cat >"$timer" <<EOF
    [Unit]
    Description=Vault Sync timer for $path
    
    [Timer]
    OnBootSec=1min
    OnUnitActiveSec=${interval_seconds}s
    Unit=$id.service
    
    [Install]
    WantedBy=timers.target
    EOF
    
      systemctl --user daemon-reload
      systemctl --user enable --now "$id.timer"
      state_set "$path" scheduler "systemd"
      state_set "$path" scheduler_id "$id"
      note "Installed systemd user timer [$id.timer] for [$path]."
    }
    
    install_cron_schedule() {
      local path interval_seconds minutes id wrapper temp
      path="$1"
      interval_seconds="$2"
      minutes="$(interval_to_cron_minutes "$interval_seconds")"
      id="$(schedule_id_for_path "$path")"
      wrapper="$(make_schedule_wrapper "$path" "$interval_seconds")"
      temp="$(mktemp)"
    
      if crontab -l >/dev/null 2>&1; then
        crontab -l | grep -v "# $id\$" >"$temp" || true
      else
        : >"$temp"
      fi
    
      printf '*/%s * * * * /bin/bash %q # %s\n' "$minutes" "$wrapper" "$id" >>"$temp"
      crontab "$temp"
      rm -f "$temp"
      state_set "$path" scheduler "cron"
      state_set "$path" scheduler_id "$id"
      note "Installed cron schedule [$id] for [$path]."
    }
    
    remove_launchd_schedule() {
      local path id label plist
      path="$1"
      id="$(schedule_id_for_path "$path")"
      label="com.graphlit.$id"
      plist="$HOME/Library/LaunchAgents/$label.plist"
      if [[ -f "$plist" ]]; then
        launchctl unload "$plist" >/dev/null 2>&1 || true
        rm -f "$plist"
      fi
    }
    
    remove_systemd_schedule() {
      local path id unit_dir
      path="$1"
      id="$(schedule_id_for_path "$path")"
      unit_dir="$HOME/.config/systemd/user"
      if command -v systemctl >/dev/null 2>&1; then
        systemctl --user disable --now "$id.timer" >/dev/null 2>&1 || true
      fi
      rm -f "$unit_dir/$id.service" "$unit_dir/$id.timer"
      if command -v systemctl >/dev/null 2>&1; then
        systemctl --user daemon-reload >/dev/null 2>&1 || true
      fi
    }
    
    remove_cron_schedule() {
      local path id temp
      path="$1"
      id="$(schedule_id_for_path "$path")"
      temp="$(mktemp)"
      if crontab -l >/dev/null 2>&1; then
        crontab -l | grep -v "# $id\$" >"$temp" || true
        crontab "$temp"
      fi
      rm -f "$temp"
    }
    
    remove_schedule() {
      local path id
      path="$1"
      id="$(schedule_id_for_path "$path")"
      remove_launchd_schedule "$path"
      remove_systemd_schedule "$path"
      remove_cron_schedule "$path"
      rm -f "$SCHEDULE_DIR/$id.sh"
      state_set "$path" scheduler ""
      state_set "$path" scheduler_id ""
      note "Removed schedule for [$path]."
    }
    
    acquire_lock() {
      local path id lock
      path="$1"
      ensure_dirs
      id="$(state_id_for_path "$path")"
      lock="$LOCK_DIR/$id.lock"
      if ! mkdir "$lock" 2>/dev/null; then
        die "Another vault-sync process is already running for [$path]."
      fi
      ACTIVE_LOCK="$lock"
      trap 'rm -rf "$ACTIVE_LOCK"' EXIT
    }
    
    cmd_init() {
      local repo_url path remote
      repo_url="${1:-}"
      [[ -n "$repo_url" ]] || die "Usage: vault-sync init <repo-url> [path]"
      path="$(absolute_path "${2:-$(default_vault_path "$repo_url")}")"
      require_command git
      ensure_dirs
    
      if [[ -d "$path/.git" ]]; then
        remote="$(git -C "$path" config --get remote.origin.url || true)"
        [[ -n "$remote" ]] || die "Existing repository [$path] has no origin remote."
        remote_matches "$remote" "$repo_url" || die "Existing repository [$path] points at [$remote], not [$repo_url]."
        note "Using existing Vault mirror [$path]."
      else
        if [[ -e "$path" ]] && [[ -n "$(find "$path" -mindepth 1 -maxdepth 1 -print -quit 2>/dev/null)" ]]; then
          die "Path [$path] exists and is not an empty Git repository."
        fi
        mkdir -p "$(dirname "$path")"
        git clone "$repo_url" "$path"
        note "Cloned Vault repository to [$path]."
      fi
    
      state_set "$path" path "$path"
      state_set "$path" repo_url "$repo_url"
      state_set "$path" initialized_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
      note "Vault configured. Run [vault-sync pull \"$path\"] to refresh it."
    }
    
    cmd_pull() {
      local path commit
      path="$(resolve_vault_path "${1:-}")"
      require_command git
      require_git_repo "$path"
      acquire_lock "$path"
    
      if worktree_dirty "$path"; then
        die "Refusing to pull because [$path] has local changes."
      fi
    
      git -C "$path" fetch --prune
      git -C "$path" pull --ff-only
      commit="$(git -C "$path" rev-parse HEAD)"
      state_set "$path" path "$path"
      state_set "$path" repo_url "$(git -C "$path" config --get remote.origin.url || true)"
      state_set "$path" last_success "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
      state_set "$path" last_commit "$commit"
      note "Vault [$path] is current at [$commit]."
    }
    
    cmd_status() {
      local path json remote branch commit dirty last_success scheduler count
      json="false"
      path=""
      while [[ "$#" -gt 0 ]]; do
        case "$1" in
          --json) json="true" ;;
          *) path="$1" ;;
        esac
        shift
      done
    
      path="$(resolve_vault_path "$path")"
      require_git_repo "$path"
      remote="$(git -C "$path" config --get remote.origin.url || true)"
      branch="$(git -C "$path" symbolic-ref --short HEAD 2>/dev/null || git -C "$path" rev-parse --short HEAD)"
      commit="$(git -C "$path" rev-parse HEAD)"
      dirty="false"
      worktree_dirty "$path" && dirty="true"
      last_success="$(state_get "$path" last_success || true)"
      scheduler="$(state_get "$path" scheduler || true)"
      count="$(markdown_count "$path")"
    
      if [[ "$json" == "true" ]]; then
        printf '{\n'
        printf '  "path": "%s",\n' "$(json_escape "$path")"
        printf '  "remote": "%s",\n' "$(json_escape "$remote")"
        printf '  "branch": "%s",\n' "$(json_escape "$branch")"
        printf '  "commit": "%s",\n' "$(json_escape "$commit")"
        printf '  "dirty": %s,\n' "$dirty"
        printf '  "lastSuccessfulSync": "%s",\n' "$(json_escape "$last_success")"
        printf '  "scheduler": "%s",\n' "$(json_escape "$scheduler")"
        printf '  "markdownFileCount": %s\n' "$count"
        printf '}\n'
        return
      fi
    
      note "Path: $path"
      note "Remote: $remote"
      note "Branch: $branch"
      note "Commit: $commit"
      note "Dirty: $dirty"
      note "Last successful sync: ${last_success:-never}"
      note "Scheduler: ${scheduler:-not installed}"
      note "Markdown files: $count"
    }
    
    cmd_schedule_install() {
      local path interval interval_seconds os
      path=""
      interval="5m"
      while [[ "$#" -gt 0 ]]; do
        case "$1" in
          --every)
            shift
            interval="${1:-}"
            [[ -n "$interval" ]] || die "Missing value for [--every]."
            ;;
          *) path="$1" ;;
        esac
        shift
      done
    
      path="$(resolve_vault_path "$path")"
      require_git_repo "$path"
      interval_seconds="$(interval_to_seconds "$interval")"
      os="$(uname -s)"
    
      case "$os" in
        Darwin)
          require_command launchctl
          install_launchd_schedule "$path" "$interval_seconds"
          ;;
        Linux)
          if systemd_user_available; then
            install_systemd_schedule "$path" "$interval_seconds"
          else
            require_command crontab
            install_cron_schedule "$path" "$interval_seconds"
          fi
          ;;
        *)
          die "Unsupported platform [$os]. Use macOS, Linux, or WSL2."
          ;;
      esac
    }
    
    cmd_schedule_remove() {
      local path
      path="$(resolve_vault_path "${1:-}")"
      remove_schedule "$path"
    }
    
    doctor_line() {
      local level message
      level="$1"
      message="$2"
      printf '[%s] %s\n' "$level" "$message"
    }
    
    cmd_doctor() {
      local raw_path path failures remote os first_path
      raw_path="${1:-}"
      failures=0
      os="$(uname -s)"
    
      case "$os" in
        Darwin|Linux) doctor_line OK "Platform [$os] is supported." ;;
        *) doctor_line FAIL "Platform [$os] is unsupported. Use macOS, Linux, or WSL2."; failures=$((failures + 1)) ;;
      esac
    
      if command -v git >/dev/null 2>&1; then
        doctor_line OK "git is installed."
      else
        doctor_line FAIL "git is required."
        failures=$((failures + 1))
      fi
    
      if command -v rg >/dev/null 2>&1; then
        doctor_line OK "rg is installed."
      else
        doctor_line WARN "rg is recommended for Vault consumption."
      fi
    
      if command -v gh >/dev/null 2>&1; then
        doctor_line OK "gh is installed."
      else
        doctor_line WARN "gh is optional and only helps diagnose GitHub authentication."
      fi
    
      first_path="$(state_paths | head -n 1 || true)"
      if [[ -n "$raw_path" ]] || [[ -d ".git" ]] || [[ -n "$first_path" ]]; then
        path="$(resolve_vault_path "$raw_path")"
        if [[ -d "$path/.git" ]]; then
          doctor_line OK "Vault path [$path] is a Git repository."
          if worktree_dirty "$path"; then
            doctor_line FAIL "Vault path [$path] has local changes."
            failures=$((failures + 1))
          else
            doctor_line OK "Vault worktree is clean."
          fi
          remote="$(git -C "$path" config --get remote.origin.url || true)"
          if [[ -n "$remote" ]]; then
            doctor_line OK "Origin remote is [$remote]."
            if git ls-remote "$remote" HEAD >/dev/null 2>&1; then
              doctor_line OK "Origin remote is reachable."
            else
              doctor_line WARN "Origin remote was not reachable from this environment."
            fi
          else
            doctor_line FAIL "No origin remote configured."
            failures=$((failures + 1))
          fi
          if [[ -n "$(state_get "$path" scheduler || true)" ]]; then
            doctor_line OK "Scheduler is recorded as [$(state_get "$path" scheduler)]."
          else
            doctor_line WARN "No scheduler is recorded for this Vault."
          fi
        else
          doctor_line WARN "Vault path [$path] does not exist yet or is not a Git repository."
        fi
      else
        doctor_line WARN "No Vault path provided and no configured Vault was found."
      fi
    
      if [[ "$failures" -gt 0 ]]; then
        exit 1
      fi
    }
    
    main() {
      local command="${1:-}"
      if [[ -z "$command" ]]; then
        usage
        exit 1
      fi
      shift || true
    
      case "$command" in
        init) cmd_init "$@" ;;
        pull) cmd_pull "$@" ;;
        status) cmd_status "$@" ;;
        schedule)
          case "${1:-}" in
            install) shift; cmd_schedule_install "$@" ;;
            remove) shift; cmd_schedule_remove "$@" ;;
            *) die "Usage: vault-sync schedule install|remove [path]" ;;
          esac
          ;;
        doctor) cmd_doctor "$@" ;;
        version|--version|-v) note "$APP_NAME $VERSION" ;;
        help|--help|-h) usage ;;
        search|query|read|summarize|rank|index)
          die "[$command] is intentionally unsupported. Use filesystem tools such as [rg], [ls], [cat], and [sed]."
          ;;
        *) die "Unknown command [$command]. Run [vault-sync help]." ;;
      esac
    }
    
    main "$@"
    
  • docs/agent-install-guide.md5.8 KB8a1af17bda95upstream ↗
    # Agent Install Guide
    
    This guide explains how to make Vault Sync available to Codex, Claude Code, and OpenClaw. Vault Sync is only for consuming an existing Vault Git repository as local files. Vault creation and management stay in the app that generated the Vault.
    
    ## What You Need
    
    - A Vault Git repository URL.
    - A local destination folder, such as `~/vaults/my-vault`.
    - macOS, Linux, or WSL2.
    - Git authentication already set up for the Vault repository.
    
    Native Windows PowerShell and Command Prompt are not currently supported. On Windows, run the agent and Vault Sync inside WSL2, and keep the Vault under the WSL filesystem.
    
    ## Recommended Paths
    
    Use the most native install path your agent supports:
    
    | Agent | Recommended path | Fallback |
    |---|---|---|
    | Codex | Plugin marketplace in Codex CLI `0.121.0` or newer | Skills or manual CLI |
    | Claude Code | Agent skills | Direct skill URL or manual CLI |
    | OpenClaw | Agent skills or direct skill URL | Manual CLI |
    
    The agent should set up the local mirror, then use normal filesystem tools to read it. It should not use Vault Sync as a search or query layer.
    
    ## Codex
    
    ### Plugin Marketplace
    
    This path requires Codex CLI `0.121.0` or newer.
    
    Add the Vault Sync marketplace:
    
    ```bash
    codex plugin marketplace add graphlit/vault-sync
    ```
    
    After install, use the marketplace name `graphlit-vault-sync` for maintenance:
    
    ```bash
    codex plugin marketplace upgrade graphlit-vault-sync
    codex plugin marketplace remove graphlit-vault-sync
    ```
    
    Then ask Codex:
    
    ```text
    Use the Vault Sync plugin to set up my Vault from <your-vault-repo-url>.
    ```
    
    Codex should install `vault-sync`, initialize the local folder, run `vault-sync doctor`, and ask before installing a recurring pull schedule.
    
    ### Skills Fallback
    
    If plugin marketplace support is not available in your Codex CLI version, install the skills directly:
    
    ```bash
    npx skills add graphlit/vault-sync --skill vault-sync-setup
    npx skills add graphlit/vault-sync --skill vault-sync-use
    ```
    
    Then ask Codex:
    
    ```text
    Use Vault Sync to set up my Vault from <your-vault-repo-url>.
    ```
    
    ### Direct Skill URL
    
    If Codex supports reading a skill from a URL, use one of:
    
    ```text
    https://raw.githubusercontent.com/graphlit/vault-sync/main/skill.md
    https://www.zine.ai/skill.md
    https://www.dossium.ai/skill.md
    ```
    
    ## Claude Code
    
    ### Agent Skills
    
    Install the setup and usage skills:
    
    ```bash
    npx skills add graphlit/vault-sync --skill vault-sync-setup
    npx skills add graphlit/vault-sync --skill vault-sync-use
    ```
    
    Then ask Claude Code:
    
    ```text
    Set up Vault Sync for my Vault from <your-vault-repo-url>.
    ```
    
    Claude Code should install `vault-sync`, initialize the local folder, run `vault-sync doctor`, and ask before installing a recurring pull schedule.
    
    ### Direct Skill URL
    
    If your Claude Code environment supports direct skill URLs, use one of:
    
    ```text
    https://raw.githubusercontent.com/graphlit/vault-sync/main/skill.md
    https://www.zine.ai/skill.md
    https://www.dossium.ai/skill.md
    ```
    
    ## OpenClaw
    
    ### Skill Install
    
    If OpenClaw supports GitHub-based skill installation, install:
    
    ```bash
    npx skills add graphlit/vault-sync --skill vault-sync-setup
    npx skills add graphlit/vault-sync --skill vault-sync-use
    ```
    
    Then ask OpenClaw:
    
    ```text
    Set up Vault Sync for my Vault from <your-vault-repo-url>.
    ```
    
    ### Direct Skill URL
    
    If OpenClaw supports direct skill URLs, use one of:
    
    ```text
    https://raw.githubusercontent.com/graphlit/vault-sync/main/skill.md
    https://www.zine.ai/skill.md
    https://www.dossium.ai/skill.md
    ```
    
    ## Manual Fallback
    
    Use this path when an agent cannot install skills or plugins directly:
    
    ```bash
    git clone https://github.com/graphlit/vault-sync
    cd vault-sync
    install -m 0755 bin/vault-sync ~/.local/bin/vault-sync
    
    vault-sync init <your-vault-repo-url> ~/vaults/<name>
    vault-sync pull ~/vaults/<name>
    vault-sync doctor ~/vaults/<name>
    ```
    
    To keep the Vault fresh:
    
    ```bash
    vault-sync schedule install ~/vaults/<name> --every 5m
    ```
    
    ## After Install
    
    Once the Vault is local, point the agent at the folder and say:
    
    ```text
    Use the local Vault in ~/vaults/<name>. Read README.md first. Ignore hidden control folders like .git, .zine, .dossium, .graphlit, .claude, and .codex. Use normal file tools to search and read the Markdown files.
    ```
    
    The agent can use `ls`, `rg`, `sed`, `cat`, and native file reads. Vault Sync should only be used to initialize, pull, check status, schedule pulls, or run diagnostics.
    
    ## Optional: Search Companion With QMD
    
    [QMD](https://github.com/tobi/qmd) can make a synced Vault folder easier to search. The roles are separate:
    
    - Vault Sync handles Git clone, pull, status, schedule, and diagnostics.
    - QMD searches the local Markdown files after they exist on disk.
    - The agent should use QMD to find likely files, then open the files directly when it needs the full source.
    
    If QMD is installed, add the Vault folder as a collection:
    
    ```bash
    vault-sync pull ~/vaults/<name>
    qmd collection add ~/vaults/<name> --name <name> --mask "**/*.md"
    qmd context add qmd://<name> "Local Vault synced by Vault Sync"
    qmd embed
    ```
    
    Useful QMD commands for agents:
    
    ```bash
    qmd search "<keywords>" -c <name> --json -n 10
    qmd vsearch "<natural-language question>" -c <name> --json -n 10
    qmd query "<research question>" -c <name> --json -n 10
    qmd get "path/from/result.md" --full
    ```
    
    QMD is optional. Do not install or require it unless the user asks for a stronger local search companion.
    
    ## Validation Checklist
    
    After setup, run:
    
    ```bash
    vault-sync status ~/vaults/<name>
    vault-sync doctor ~/vaults/<name>
    rg -n "<known term>" ~/vaults/<name>
    ```
    
    Expected result:
    
    - `vault-sync status` reports the current local revision.
    - `vault-sync doctor` reports Git and repository health.
    - `rg` can find text in Markdown files.
    
    If Git authentication fails, authenticate through your normal Git or GitHub CLI flow and retry `vault-sync pull`.
    
  • examples/install-claude-code.md1.2 KB4250b1b0eda4upstream ↗
    # Claude Code Install
    
    Use this when a Vault already exists in Git and Claude Code can access your local filesystem.
    
    ## Preferred: Agent Skills
    
    Install the setup and usage skills:
    
    ```bash
    npx skills add graphlit/vault-sync --skill vault-sync-setup
    npx skills add graphlit/vault-sync --skill vault-sync-use
    ```
    
    Then ask Claude Code:
    
    ```text
    Set up Vault Sync for my Vault from <your-vault-repo-url>.
    ```
    
    Claude Code should install `vault-sync`, initialize the local folder, run `vault-sync doctor`, and ask before installing a recurring pull schedule.
    
    ## Direct Skill Fallback
    
    If your environment uses direct skill URLs, point Claude Code at:
    
    ```text
    https://raw.githubusercontent.com/graphlit/vault-sync/main/skill.md
    ```
    
    ## Manual Fallback
    
    ```bash
    git clone https://github.com/graphlit/vault-sync
    cd vault-sync
    install -m 0755 bin/vault-sync ~/.local/bin/vault-sync
    
    vault-sync init <your-vault-repo-url> ~/vaults/<name>
    vault-sync schedule install ~/vaults/<name> --every 5m
    ```
    
    After setup, Claude Code should read `README.md` in the local Vault first, ignore hidden control folders, and inspect Markdown files directly with normal filesystem tools. Treat the Vault as read-only unless you explicitly want local edits.
    
  • examples/install-codex.md1.5 KB5b9689f6d6e2upstream ↗
    # Codex Install
    
    Use this when a Vault already exists in Git and Codex can access your local filesystem.
    
    ## Preferred: Codex Plugin Marketplace
    
    This path requires Codex CLI `0.121.0` or newer.
    
    Add the Vault Sync marketplace:
    
    ```bash
    codex plugin marketplace add graphlit/vault-sync
    ```
    
    After install, use the marketplace name `graphlit-vault-sync` for maintenance:
    
    ```bash
    codex plugin marketplace upgrade graphlit-vault-sync
    codex plugin marketplace remove graphlit-vault-sync
    ```
    
    Then ask Codex:
    
    ```text
    Use the Vault Sync plugin to set up my Vault from <your-vault-repo-url>.
    ```
    
    Codex should install `vault-sync`, initialize the local folder, run `vault-sync doctor`, and ask before installing a recurring pull schedule.
    
    ## Skill Fallback
    
    If plugin marketplace support is not available in your Codex CLI version, install the skills directly:
    
    ```bash
    npx skills add graphlit/vault-sync --skill vault-sync-setup
    npx skills add graphlit/vault-sync --skill vault-sync-use
    ```
    
    You can also point Codex at the direct skill entrypoint:
    
    ```text
    https://raw.githubusercontent.com/graphlit/vault-sync/main/skill.md
    ```
    
    ## Manual Fallback
    
    ```bash
    git clone https://github.com/graphlit/vault-sync
    cd vault-sync
    install -m 0755 bin/vault-sync ~/.local/bin/vault-sync
    
    vault-sync init <your-vault-repo-url> ~/vaults/<name>
    vault-sync schedule install ~/vaults/<name> --every 5m
    ```
    
    After setup, Codex should read `README.md` in the local Vault first, ignore hidden control folders, and inspect Markdown files directly with normal filesystem tools.
    
  • examples/install-openclaw.md1.1 KBffb6333cbaceupstream ↗
    # OpenClaw Install
    
    Use this when a Vault already exists in Git and OpenClaw can access your local filesystem.
    
    ## Preferred: Skill Entry
    
    If OpenClaw can install agent skills from GitHub, install:
    
    ```bash
    npx skills add graphlit/vault-sync --skill vault-sync-setup
    npx skills add graphlit/vault-sync --skill vault-sync-use
    ```
    
    If it uses direct skill URLs, point it at:
    
    ```text
    https://raw.githubusercontent.com/graphlit/vault-sync/main/skill.md
    ```
    
    Then ask OpenClaw:
    
    ```text
    Set up Vault Sync for my Vault from <your-vault-repo-url>.
    ```
    
    OpenClaw should install `vault-sync`, initialize the local folder, run `vault-sync doctor`, and ask before installing a recurring pull schedule.
    
    ## Manual Fallback
    
    ```bash
    git clone https://github.com/graphlit/vault-sync
    cd vault-sync
    install -m 0755 bin/vault-sync ~/.local/bin/vault-sync
    
    vault-sync init <your-vault-repo-url> ~/vaults/<name>
    vault-sync schedule install ~/vaults/<name> --every 5m
    ```
    
    After setup, OpenClaw should read `README.md` in the local Vault first, ignore hidden control folders, and inspect Markdown files directly with normal filesystem tools.
    
  • LICENSE1.0 KBf227b16be112upstream ↗
    MIT License
    
    Copyright (c) 2026 Graphlit
    
    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:
    
    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
    
  • plugins/vault-sync/.codex-plugin/plugin.json975 B50861295a93fupstream ↗
    {
      "name": "vault-sync",
      "version": "0.1.0",
      "description": "Install and use Vault Sync for filesystem-based Vault consumption.",
      "author": {
        "name": "Graphlit",
        "url": "https://github.com/graphlit/vault-sync"
      },
      "homepage": "https://github.com/graphlit/vault-sync",
      "repository": "https://github.com/graphlit/vault-sync",
      "license": "MIT",
      "keywords": [
        "vault",
        "git",
        "sync",
        "filesystem",
        "agent"
      ],
      "skills": "./skills/",
      "interface": {
        "displayName": "Vault Sync",
        "shortDescription": "Mirror Vault Git repositories locally.",
        "longDescription": "Vault Sync helps Codex install a small Git-based sync script, mirror an existing Vault to local Markdown files, and consume those files with normal filesystem tools.",
        "developerName": "Graphlit",
        "category": "Productivity",
        "defaultPrompt": [
          "Set up Vault Sync for my Vault.",
          "Use my local Vault folder to answer this."
        ]
      }
    }
    
  • plugins/vault-sync/skills/vault-sync-setup/scripts/install-vault-sync.sh1.2 KBa459fe2ff128upstream ↗
    #!/usr/bin/env bash
    set -euo pipefail
    
    install_dir="${VAULT_SYNC_INSTALL_DIR:-$HOME/.local/bin}"
    target="$install_dir/vault-sync"
    
    case "$(uname -s)" in
      Darwin|Linux) ;;
      *)
        echo "Vault Sync currently supports macOS, Linux, and WSL2 Linux environments." >&2
        exit 1
        ;;
    esac
    
    if ! command -v git >/dev/null 2>&1; then
      echo "git is required before installing Vault Sync." >&2
      exit 1
    fi
    
    mkdir -p "$install_dir"
    
    script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    repo_root="${VAULT_SYNC_REPO_ROOT:-$(cd "$script_dir/../../.." && pwd)}"
    
    if [[ -f "$repo_root/bin/vault-sync" ]]; then
      install -m 0755 "$repo_root/bin/vault-sync" "$target"
    elif command -v curl >/dev/null 2>&1; then
      curl -fsSL https://raw.githubusercontent.com/graphlit/vault-sync/main/bin/vault-sync -o "$target"
      chmod 0755 "$target"
    elif command -v wget >/dev/null 2>&1; then
      wget -qO "$target" https://raw.githubusercontent.com/graphlit/vault-sync/main/bin/vault-sync
      chmod 0755 "$target"
    else
      echo "Install from a checkout or install curl/wget to download Vault Sync." >&2
      exit 1
    fi
    
    echo "Installed vault-sync at $target"
    
    case ":$PATH:" in
      *":$install_dir:"*) ;;
      *) echo "Note: $install_dir is not on PATH for this shell." >&2 ;;
    esac
    
  • plugins/vault-sync/skills/vault-sync-setup/scripts/setup-vault.sh1.1 KBe9ae08c0f83fupstream ↗
    #!/usr/bin/env bash
    set -euo pipefail
    
    usage() {
      cat <<'USAGE'
    Usage: setup-vault.sh <vault-repo-url> [path] [--schedule] [--every 5m]
    USAGE
    }
    
    if [[ $# -lt 1 ]]; then
      usage >&2
      exit 1
    fi
    
    repo_url="$1"
    shift
    
    path=""
    schedule="false"
    every="5m"
    
    while [[ $# -gt 0 ]]; do
      case "$1" in
        --schedule)
          schedule="true"
          shift
          ;;
        --every)
          every="${2:-}"
          if [[ -z "$every" ]]; then
            usage >&2
            exit 1
          fi
          shift 2
          ;;
        -*)
          usage >&2
          exit 1
          ;;
        *)
          if [[ -n "$path" ]]; then
            usage >&2
            exit 1
          fi
          path="$1"
          shift
          ;;
      esac
    done
    
    if [[ -z "$path" ]]; then
      name="${repo_url##*/}"
      name="${name%.git}"
      path="$HOME/vaults/$name"
    fi
    
    if ! command -v vault-sync >/dev/null 2>&1; then
      script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
      bash "$script_dir/install-vault-sync.sh"
    fi
    
    vault-sync init "$repo_url" "$path"
    vault-sync pull "$path"
    vault-sync doctor "$path"
    
    if [[ "$schedule" == "true" ]]; then
      vault-sync schedule install "$path" --every "$every"
    fi
    
    echo "Vault ready at $path"
    
  • skills/vault-sync-setup/scripts/install-vault-sync.sh1.2 KBa459fe2ff128upstream ↗
    #!/usr/bin/env bash
    set -euo pipefail
    
    install_dir="${VAULT_SYNC_INSTALL_DIR:-$HOME/.local/bin}"
    target="$install_dir/vault-sync"
    
    case "$(uname -s)" in
      Darwin|Linux) ;;
      *)
        echo "Vault Sync currently supports macOS, Linux, and WSL2 Linux environments." >&2
        exit 1
        ;;
    esac
    
    if ! command -v git >/dev/null 2>&1; then
      echo "git is required before installing Vault Sync." >&2
      exit 1
    fi
    
    mkdir -p "$install_dir"
    
    script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
    repo_root="${VAULT_SYNC_REPO_ROOT:-$(cd "$script_dir/../../.." && pwd)}"
    
    if [[ -f "$repo_root/bin/vault-sync" ]]; then
      install -m 0755 "$repo_root/bin/vault-sync" "$target"
    elif command -v curl >/dev/null 2>&1; then
      curl -fsSL https://raw.githubusercontent.com/graphlit/vault-sync/main/bin/vault-sync -o "$target"
      chmod 0755 "$target"
    elif command -v wget >/dev/null 2>&1; then
      wget -qO "$target" https://raw.githubusercontent.com/graphlit/vault-sync/main/bin/vault-sync
      chmod 0755 "$target"
    else
      echo "Install from a checkout or install curl/wget to download Vault Sync." >&2
      exit 1
    fi
    
    echo "Installed vault-sync at $target"
    
    case ":$PATH:" in
      *":$install_dir:"*) ;;
      *) echo "Note: $install_dir is not on PATH for this shell." >&2 ;;
    esac
    
  • skills/vault-sync-setup/scripts/setup-vault.sh1.1 KBe9ae08c0f83fupstream ↗
    #!/usr/bin/env bash
    set -euo pipefail
    
    usage() {
      cat <<'USAGE'
    Usage: setup-vault.sh <vault-repo-url> [path] [--schedule] [--every 5m]
    USAGE
    }
    
    if [[ $# -lt 1 ]]; then
      usage >&2
      exit 1
    fi
    
    repo_url="$1"
    shift
    
    path=""
    schedule="false"
    every="5m"
    
    while [[ $# -gt 0 ]]; do
      case "$1" in
        --schedule)
          schedule="true"
          shift
          ;;
        --every)
          every="${2:-}"
          if [[ -z "$every" ]]; then
            usage >&2
            exit 1
          fi
          shift 2
          ;;
        -*)
          usage >&2
          exit 1
          ;;
        *)
          if [[ -n "$path" ]]; then
            usage >&2
            exit 1
          fi
          path="$1"
          shift
          ;;
      esac
    done
    
    if [[ -z "$path" ]]; then
      name="${repo_url##*/}"
      name="${name%.git}"
      path="$HOME/vaults/$name"
    fi
    
    if ! command -v vault-sync >/dev/null 2>&1; then
      script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
      bash "$script_dir/install-vault-sync.sh"
    fi
    
    vault-sync init "$repo_url" "$path"
    vault-sync pull "$path"
    vault-sync doctor "$path"
    
    if [[ "$schedule" == "true" ]]; then
      vault-sync schedule install "$path" --every "$every"
    fi
    
    echo "Vault ready at $path"
    
  • tests/smoke.sh1.3 KB68e1dbea9706upstream ↗
    #!/usr/bin/env bash
    set -euo pipefail
    
    ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
    TMPDIR_ROOT="$(mktemp -d)"
    SRC="$TMPDIR_ROOT/source"
    VAULT="$TMPDIR_ROOT/vault"
    CONFIG="$TMPDIR_ROOT/config"
    
    cleanup() {
      rm -rf "$TMPDIR_ROOT"
    }
    trap cleanup EXIT
    
    git init -b main "$SRC" >/dev/null
    git -C "$SRC" config user.email [email protected]
    git -C "$SRC" config user.name "Vault Sync Test"
    
    printf '# Test Vault\n\nhello vault\n' >"$SRC/README.md"
    git -C "$SRC" add README.md
    git -C "$SRC" commit -m 'initial vault' >/dev/null
    
    VAULT_SYNC_CONFIG_DIR="$CONFIG" bash "$ROOT_DIR/bin/vault-sync" init "$SRC" "$VAULT"
    VAULT_SYNC_CONFIG_DIR="$CONFIG" bash "$ROOT_DIR/bin/vault-sync" status "$VAULT" >/dev/null
    VAULT_SYNC_CONFIG_DIR="$CONFIG" bash "$ROOT_DIR/bin/vault-sync" status "$VAULT" --json >/dev/null
    
    printf '\nsecond line\n' >>"$SRC/README.md"
    git -C "$SRC" add README.md
    git -C "$SRC" commit -m 'update vault' >/dev/null
    
    VAULT_SYNC_CONFIG_DIR="$CONFIG" bash "$ROOT_DIR/bin/vault-sync" pull "$VAULT"
    VAULT_SYNC_CONFIG_DIR="$CONFIG" bash "$ROOT_DIR/bin/vault-sync" doctor "$VAULT"
    
    if VAULT_SYNC_CONFIG_DIR="$CONFIG" bash "$ROOT_DIR/bin/vault-sync" search "$VAULT" >/dev/null 2>&1; then
      printf 'search unexpectedly succeeded\n' >&2
      exit 1
    fi
    
    printf 'vault-sync smoke test passed\n'
    

Plain-text copy, no login: /skill-bundles/graphlit-vault-sync.md

// REPO STATS

2 stars