Skip to content
    ↑↓ select↵ openesc close
    English中文
    dylanrussellmd

    Chezmoi Guard

    v1.1.2Other
    @dylanrussell/chezmoi-guard

    Redirect opencode agent edits to chezmoi source files, then sync. Intercepts edit/write/apply_patch so agents never edit chezmoi-managed targets out-of-band.

    GitHub stars

    0

    Monthly installs

    54

    Composite scoreSCORE

    29.2

    Multi-signal model

    Last commit

    1 month ago

    2026-07-17

    Install and configure

    opencode.json

    Writes to this project's opencode.json — applies to this repository only.

    opencode.json

    {
      "$schema": "https://opencode.ai/config.json",
      "plugin": ["@dylanrussell/chezmoi-guard@1.1.2"]
    }

    opencode loads npm dependencies through its embedded runtime on startup and caches them locally — no manual global install needed.

    chezmoi-guard

    Stop opencode agents from editing chezmoi-managed files out-of-band. Intercepts edit / write / apply_patch, redirects to the chezmoi source, then syncs.

    npm version license node types: TypeScript tested with vitest


    What it does

    When an opencode agent edits a file that lives under your chezmoi source, the edit lands on the rendered target — not the source. The next chezmoi apply silently reverts it. This plugin fixes that transparently:

    • Intercepts edit, write, and apply_patch tool calls.
    • Asks chezmoi managed whether the target is chezmoi-managed.
    • If it is, rewrites the tool args to operate on the source file.
    • After the tool runs, executes chezmoi apply --no-tty <target> to sync the target from the freshly-edited source.
    • Advises read calls: reading a target whose source is a template, modify_ script, or encrypted entry prepends guidance pointing at the editable source — without rewriting the read or hiding the real on-disk content.
    • Emits a TUI toast on every redirect, warning, or block.

    Install

    // ~/.config/opencode/opencode.json
    {
      "plugin": [
        "@dylanrussell/chezmoi-guard"
      ]
    }
    

    Requires the chezmoi CLI on PATH. The plugin silently no-ops when chezmoi is missing.

    Source-type handling

    Source prefix / suffix Behaviour
    dot_ / private_ / executable_ / empty_ (normal) Redirect to source, chezmoi apply after
    exact_ (directory attribute) Files inside an exact_ dir redirect normally — exact_ only prunes absent target entries, it does not make files structural. Directories are excluded upstream by chezmoi managed --include=files,symlinks.
    .tmpl (template) edit → redirect to source + guidance; write → warn (hits rendered target, lost on apply)
    symlink_ Read the link target, redirect to the actual file, chezmoi apply after
    modify_ Passthrough with warning (partial file manager; target edits may be overwritten)
    encrypted_ / .age / .asc BLOCKED with guidance (use chezmoi edit instead)
    run_ / directories Skipped (scripts / structural markers)

    Read advisory

    read is never redirected — the agent always sees the real on-disk target bytes. But for three source kinds, a guidance block is prepended to the read output because a naive follow-up edit would misfire:

    Source kind Why reads need an advisory
    .tmpl (template) Rendered target bytes ≠ source bytes. An edit oldString built from the rendered content will not match the source file the guard redirects to. The advisory says: read the source first.
    modify_ The target is script-managed state; persistent changes belong in the modify script, so the advisory points at it.
    encrypted_ / .age / .asc Reading the plaintext target is fine, but edits are blocked — the advisory pre-empts a doomed edit plan with chezmoi edit.

    Reads of normal/symlink targets stay silent: their edits are transparently redirected anyway, and a banner on every dotfile read would be pure context noise.

    Sync semantics

    The guard edits the source before the target is touched, so the normal chezmoi apply is non-interactive (the target is clean). The --no-tty flag is added so that if the target has drifted out-of-band (MM status — a prior manual edit, or a template/modify passthrough), chezmoi apply fails safe: it exits non-zero and leaves the user's out-of-band edit intact, instead of hanging on a TTY prompt or silently discarding changes with --force.

    Debug

    CHEZMOI_GUARD_DEBUG=1 opencode
    

    Emits [chezmoi-guard] ... lines to stderr for every redirect, skip, warn, and block.

    Development

    npm install
    npm run build        # tsup → dist/plugin.js + dist/plugin.d.ts
    npm test             # vitest run --coverage
    npm run lint         # biome check
    npm run typecheck    # tsc --noEmit
    

    License

    MIT © Dylan Russell