Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
Cameron Sjo avatar

Obsidi Backup

  • 1 repo stars
  • Updated June 20, 2026
  • cameronsjo/obsidi-backup

Vault backup sidecar with AI commit messages and restic cloud storage

About

obsidi-backup is a Claude Code skill in the Git & Pull Requests category. Vault backup sidecar with AI commit messages and restic cloud storage

  • obsidi-backup
  • Git & Pull Requests
  • AI-coding skill

Obsidi Backup by the numbers

  • Data as of Jul 11, 2026 (Skillselion catalog sync)
/plugin marketplace add cameronsjo/obsidi-backup
/plugin install obsidi-backup@obsidi-backup

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
repo stars1
Last updatedJune 20, 2026
Repositorycameronsjo/obsidi-backup

What it does

Vault backup sidecar with AI commit messages and restic cloud storage

README.md

obsidi-backup

Build and Push License: PolyForm Noncommercial Container Registry

A lightweight sidecar container that automatically backs up your Obsidian vault with git versioning and cloud storage via restic.

Why?

Obsidian Sync is great, but it's not a backup. This container provides:

  • Git history - Every change tracked, browse history, diff versions
  • Cloud backup - Encrypted, deduplicated backups to Azure, S3, B2, or any restic backend
  • AI commit messages - Optional Claude-powered summaries of what changed
  • Notifications - Know when backups succeed or fail

Features

  • File watching - Real-time monitoring with configurable debounce
  • Git versioning - Auto-commits with AI-generated or timestamp messages
  • Cloud backup - Restic to Azure, S3, B2, SFTP, or local storage
  • Health endpoint - HTTP /health for monitoring and orchestration
  • Configurable retention - Customize daily, weekly, monthly snapshots
  • Notifications - Discord, Slack, or generic webhooks
  • Dry run mode - Test configuration without making changes
  • Multi-arch - Runs on amd64 and arm64 (Raspberry Pi, Apple Silicon)

Quick Start

services:
  vault-backup:
    image: ghcr.io/cameronsjo/obsidi-backup:latest
    environment:
      TZ: America/Chicago
      # Storage backend (Azure example)
      AZURE_ACCOUNT_NAME: mystorageaccount
      AZURE_ACCOUNT_KEY: ${AZURE_ACCOUNT_KEY}
      RESTIC_REPOSITORY: azure:obsidian-backup:/vault
      RESTIC_PASSWORD: ${RESTIC_PASSWORD}
      # Optional: AI commit messages
      ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
      # Optional: Notifications
      DISCORD_WEBHOOK_URL: ${DISCORD_WEBHOOK_URL}
    volumes:
      - /path/to/your/vault:/vault
    ports:
      - "8080:8080"

After starting, initialize the restic repository:

docker exec vault-backup restic init

Architecture

┌─────────────────────────────────────────────────────────────┐
│                    Obsidian Vault Backup                    │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────┐    ┌──────────┐    ┌────────┐    ┌─────────┐  │
│  │ Watchdog│───▶│ Debounce │───▶│  Git   │───▶│ Restic  │  │
│  │ Monitor │    │ (5 min)  │    │ Commit │    │ Backup  │  │
│  └─────────┘    └──────────┘    └────────┘    └─────────┘  │
│       │                              │             │        │
│       │                              ▼             │        │
│       │                        ┌──────────┐       │        │
│       │                        │   LLM    │       │        │
│       │                        │ (Haiku)  │       │        │
│       │                        └──────────┘       │        │
│       │                                           ▼        │
│       │         ┌──────────┐              ┌───────────┐    │
│       └────────▶│  Health  │              │  Notify   │    │
│                 │  Server  │              │ (Discord) │    │
│                 └──────────┘              └───────────┘    │
│                      │                                      │
└──────────────────────┼──────────────────────────────────────┘
                       ▼
                  :8080/health

Flow:

  1. Watchdog monitors the vault for file changes
  2. Debounce waits for 5 minutes of inactivity (configurable)
  3. Git commit stages all changes, generates commit message (AI or timestamp)
  4. Restic backup encrypts and uploads to cloud storage
  5. Prune removes old snapshots per retention policy
  6. Notify sends success/failure alerts

Configuration

Storage Backends

Restic supports many backends. Set RESTIC_REPOSITORY accordingly:

Backend Repository Format Additional Env Vars
Azure Blob azure:container:/path AZURE_ACCOUNT_NAME, AZURE_ACCOUNT_KEY
AWS S3 s3:s3.amazonaws.com/bucket AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
Backblaze B2 b2:bucket:/path B2_ACCOUNT_ID, B2_ACCOUNT_KEY
SFTP sftp:user@host:/path SSH key or RESTIC_PASSWORD
Local /path/to/backup -
REST Server rest:http://host:8000/ -

See restic documentation for all options.

Environment Variables

Required
Variable Description
RESTIC_REPOSITORY Restic repository URL
RESTIC_PASSWORD Restic encryption password

Plus backend-specific variables (see table above).

Paths & Timing
Variable Default Description
VAULT_PATH /vault Path to Obsidian vault
DEBOUNCE_SECONDS 300 Wait time after last change (5 min)
HEALTH_PORT 8080 Health endpoint port
Git
Variable Default Description
GIT_USER_NAME Obsidian Backup Commit author name
GIT_USER_EMAIL backup@local Commit author email
AI Commit Messages

Uses Claude Haiku 4.5 to generate meaningful commit messages from changed filenames.

Variable Default Description
ANTHROPIC_API_KEY - Anthropic API key
ANTHROPIC_MODEL claude-haiku-4-5-20251001 Model to use

Or use any OpenAI-compatible API:

Variable Default Description
LLM_API_URL - API endpoint URL
LLM_API_KEY - API key
LLM_MODEL anthropic/claude-haiku-4.5 Model identifier
Retention Policy
Variable Default Description
RETENTION_DAILY 7 Daily snapshots to keep
RETENTION_WEEKLY 4 Weekly snapshots to keep
RETENTION_MONTHLY 12 Monthly snapshots to keep
Notifications
Variable Default Description
NOTIFY_LEVEL all all, errors, success, or none
DISCORD_WEBHOOK_URL - Discord webhook
SLACK_WEBHOOK_URL - Slack incoming webhook
WEBHOOK_URL - Generic webhook (JSON POST)
Feature Flags
Variable Default Description
DRY_RUN false Test mode - no commits or backups
PIPELINE_STALE_THRESHOLD_SECONDS 7200 Seconds of watcher silence before sync_pipeline_status goes stale

Health Endpoints

/health — liveness probe

curl http://localhost:8080/health
{
  "status": "healthy",
  "uptime_seconds": 3600
}

Thin liveness wrapper. status is unhealthy when there are pending changes and no backup in 24+ hours. Safe to use as a Kubernetes/Docker liveness probe.

/status — full pipeline signal

curl http://localhost:8080/status
{
  "status": "healthy",
  "sync_pipeline_status": "healthy",
  "last_watcher_event_at": "2024-01-15T10:30:00Z",
  "last_change_detected_at": "2024-01-14T09:12:44Z",
  "last_commit_at": "2024-01-14T09:17:44Z",
  "last_push_at": "2024-01-14T09:17:46Z",
  "last_restic_snapshot_at": "2024-01-14T09:17:51Z",
  "pipeline_stale_threshold_seconds": 7200,
  "seconds_since_watcher_event": 412,
  "pending_changes": false,
  "uptime_seconds": 3600,
  "upstream_heartbeat": null
}

sync_pipeline_status detects when the upstream sync process (e.g. obsidi-headless) has gone silent, even if no commit-worthy changes have arrived:

  • healthy — watcher has seen filesystem activity within the threshold window
  • stale — no filesystem activity for longer than PIPELINE_STALE_THRESHOLD_SECONDS (default 2h). The upstream writer has likely stopped.
  • unknown — service just started, no events recorded yet

The key insight: even when the vault is content-quiet, obsidi-headless's ob sync --continuous writes ephemeral metadata files (.obsidian/workspace.json, lockfiles) at sub-hour cadence. If watcher events stop arriving, the sync process has almost certainly crashed — not just "nothing to sync."

Gatus monitoring condition

- name: obsidi-backup-pipeline
  url: http://obsidi-backup:8080/status
  interval: 5m
  conditions:
    - "[STATUS] == 200"
    - "[BODY].sync_pipeline_status == healthy"

Status values:

  • healthy - Everything working normally
  • unhealthy - Changes pending but no backup in 24+ hours

Notifications

Discord

Create a webhook in Discord (Server Settings → Integrations → Webhooks):

DISCORD_WEBHOOK_URL: https://discord.com/api/webhooks/123456/abcdef

Slack

Create an Incoming Webhook in Slack:

SLACK_WEBHOOK_URL: https://hooks.slack.com/services/T.../B.../...

Generic Webhook

For Ntfy, Gotify, Home Assistant, n8n, or any HTTP endpoint:

WEBHOOK_URL: https://your-service.com/webhook

Payload format:

{
  "title": "Vault Backup Complete",
  "message": "Committed and backed up: 3 files changed",
  "status": "success",
  "timestamp": "2024-01-15T10:30:00Z"
}

Restore

List available snapshots:

docker exec vault-backup restic snapshots

Restore the latest snapshot:

docker exec vault-backup restic restore latest --target /restore

Restore a specific snapshot:

docker exec vault-backup restic restore abc123 --target /restore

Mount snapshots as a filesystem (for browsing):

docker exec -it vault-backup restic mount /mnt

Troubleshooting

"Restic repository not initialized"

Run restic init after first start:

docker exec vault-backup restic init

"Vault directory is not writable"

The container needs write access to create git commits. Remove :ro from your volume mount:

volumes:
  - /path/to/vault:/vault  # Not /path/to/vault:/vault:ro

No backups happening

  1. Check if debounce period elapsed (default 5 minutes)
  2. Verify health endpoint: curl http://localhost:8080/health
  3. Check container logs: docker logs vault-backup

AI commit messages not working

  1. Verify ANTHROPIC_API_KEY is set correctly
  2. Check logs for API errors
  3. Fallback timestamp messages will be used if AI fails

Notifications not sending

  1. Verify webhook URL is correct
  2. Check NOTIFY_LEVEL setting
  3. Test webhook manually with curl

Development

# Install dependencies
pip install -e ".[dev]"

# Run locally
VAULT_PATH=/path/to/vault python -m vault_backup

# Run tests
pytest

# Lint
ruff check src/

License

PolyForm Noncommercial 1.0.0. Commercial use requires a separate license — get in touch

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.