obsidian-sync 0.1.1
A CLI tool to synchronize Obsidian vaults using GitHub.
Requires Python: <4.0,>=3.9

# Obsidian GitHub Sync

A powerful Python CLI tool to synchronize your Obsidian vaults with GitHub, enabling seamless backup and multi-device sync.

## Features

- 🔄 **Automatic Vault Detection**: Automatically finds your Obsidian vault on macOS, Windows, and Linux
- 📤 **Easy Push/Pull**: Simple commands to sync your notes with GitHub
- ⏰ **Scheduled Sync**: Set up automated syncing with your OS's native scheduler
- 🔒 **Secure**: Uses Git's proven synchronization technology
- 🌍 **Cross-Platform**: Works on macOS, Windows, and Linux

## Prerequisites

- **Python 3.9+**: Make sure Python is installed on your system
- **Git**: Git must be installed and accessible from your command line
- **GitHub Account**: You'll need a GitHub account and repository for storing your vault

## Installation

Install the tool via pip:

```bash
pip install obsidian-sync
```

Alternatively, you can install from source:

```bash
git clone https://github.com/your-username/obsidian-sync.git
cd obsidian-sync
pip install -e .
```

## Quick Start

### 1. Create a GitHub Repository

First, create a new, **empty** repository on GitHub to store your Obsidian vault. You can make it private for security.

### 2. Initialize Sync

Run the `init` command to connect your vault to the GitHub repository:

```bash
obsidian-sync init --repo-url git@github.com:your-username/your-repo-name.git
```

The tool will automatically detect your Obsidian vault location. If auto-detection fails, you can specify the path manually:

```bash
obsidian-sync init --vault-path "/path/to/your/vault" --repo-url git@github.com:your-username/your-repo-name.git
```

This command will:
- Initialize a Git repository in your vault
- Create a `.gitignore` file to exclude temporary files
- Perform the first sync, pushing all your existing notes to GitHub

### 3. Manual Syncing

Once initialized, you can manually sync your vault at any time:

**Push local changes to GitHub:**
```bash
obsidian-sync push
```

**Pull remote changes from GitHub:**
```bash
obsidian-sync pull
```

### 4. Automated Syncing (Optional)

Set up automatic syncing to run every 15 minutes:

```bash
obsidian-sync cron-setup --schedule "*/15 * * * *"
```

This command will provide you with instructions specific to your operating system:
- **Linux/macOS**: Instructions for setting up a cron job
- **Windows**: Instructions for setting up a Task Scheduler task

## Usage

### Commands

#### `init`

Initialize a new sync configuration for your Obsidian vault.

```bash
obsidian-sync init [OPTIONS]
```

**Options:**
- `--vault-path PATH`: Path to your Obsidian vault (optional, auto-detected if not provided)
- `--repo-url URL`: GitHub repository URL (required)

**Examples:**
```bash
# Auto-detect vault location
obsidian-sync init --repo-url git@github.com:username/vault-backup.git

# Specify vault path manually
obsidian-sync init --vault-path ~/Documents/MyVault --repo-url git@github.com:username/vault-backup.git
```

#### `push`

Push local changes to the remote GitHub repository.

```bash
obsidian-sync push [OPTIONS]
```

**Options:**
- `--vault-path PATH`: Path to your Obsidian vault (optional, uses configured vault if not provided)

**Examples:**
```bash
# Push changes from configured vault
obsidian-sync push

# Push changes from specific vault
obsidian-sync push --vault-path ~/Documents/MyVault
```

#### `pull`

Pull remote changes from GitHub to your local vault.

```bash
obsidian-sync pull [OPTIONS]
```

**Options:**
- `--vault-path PATH`: Path to your Obsidian vault (optional, uses configured vault if not provided)

**Examples:**
```bash
# Pull changes to configured vault
obsidian-sync pull

# Pull changes to specific vault
obsidian-sync pull --vault-path ~/Documents/MyVault
```

#### `cron-setup`

Generate instructions for setting up automated syncing.

```bash
obsidian-sync cron-setup [OPTIONS]
```

**Options:**
- `--schedule CRON`: Cron schedule expression (default: `*/15 * * * *` for every 15 minutes)
- `--vault-path PATH`: Path to your Obsidian vault (optional, uses configured vault if not provided)

**Examples:**
```bash
# Set up sync every 15 minutes
obsidian-sync cron-setup --schedule "*/15 * * * *"

# Set up sync every hour
obsidian-sync cron-setup --schedule "0 * * * *"

# Set up sync twice a day (8 AM and 8 PM)
obsidian-sync cron-setup --schedule "0 8,20 * * *"
```

**Cron Schedule Format:**
```
* * * * *
│ │ │ │ │
│ │ │ │ └─── Day of week (0-7, Sunday = 0 or 7)
│ │ │ └───── Month (1-12)
│ │ └─────── Day of month (1-31)
│ └───────── Hour (0-23)
└─────────── Minute (0-59)
```

## Configuration

The tool stores configuration in `~/.config/obsidian-sync/config.json` (Linux/macOS) or `%APPDATA%\obsidian-sync\config.json` (Windows).

**Example configuration:**
```json
{
  "vaults": [
    {
      "vault_path": "/Users/jane/Documents/ObsidianVault",
      "repo_url": "git@github.com:jane/obsidian-sync.git",
      "last_sync_time": "2025-12-17T10:00:00Z"
    }
  ]
}
```

## What Gets Synced?

The tool syncs all files in your Obsidian vault, including:
- ✅ Markdown notes (`*.md`)
- ✅ Obsidian settings (`.obsidian/` directory)
- ✅ Plugins and themes
- ✅ Attachments (images, PDFs, etc.)

**Excluded files** (via `.gitignore`):
- ❌ Workspace layouts (`.obsidian/workspace*`)
- ❌ Cache files (`.obsidian/cache/`)
- ❌ Trash (`.trash/`)

## Troubleshooting

### Vault Not Found

If the tool cannot auto-detect your vault, specify the path manually:

```bash
obsidian-sync init --vault-path "/path/to/your/vault" --repo-url <URL>
```

### Git Authentication Issues

If you encounter authentication errors:

1. **SSH**: Make sure you have SSH keys set up with GitHub ([GitHub SSH Guide](https://docs.github.com/en/authentication/connecting-to-github-with-ssh))
2. **HTTPS**: Use a personal access token instead of your password ([GitHub Token Guide](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token))

### Merge Conflicts

If you edit the same file on multiple devices without syncing, you may encounter merge conflicts. To resolve:

1. Navigate to your vault directory
2. Run `git status` to see conflicted files
3. Manually edit the files to resolve conflicts
4. Run `git add .` and `git commit -m "Resolve conflicts"`
5. Run `obsidian-sync push`

## Development

### Running Tests

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

# Run all tests
pytest

# Run unit tests only
pytest tests/unit/

# Run integration tests only
pytest tests/integration/

# Run with coverage
pytest --cov=obsidian_sync
```

### Project Structure

```
src/
├── obsidian_sync/
│   ├── __init__.py
│   ├── main.py              # CLI entry point
│   ├── models.py            # Data models
│   ├── commands/            # Command implementations
│   │   ├── init.py
│   │   ├── sync.py
│   │   └── schedule.py
│   └── logic/               # Core business logic
│       ├── git_ops.py       # Git operations
│       └── vault.py         # Vault detection
tests/
├── unit/                    # Unit tests
└── integration/             # Integration tests
```

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## License

This project is licensed under the MIT License - see the LICENSE file for details.

## Acknowledgments

- Built with [Typer](https://typer.tiangolo.com/) for the CLI interface
- Uses [GitPython](https://gitpython.readthedocs.io/) for Git operations
- Inspired by the amazing [Obsidian](https://obsidian.md/) note-taking app

## Support

If you encounter any issues or have questions:
- 🐛 [Report a bug](https://github.com/your-username/obsidian-sync/issues)
- 💡 [Request a feature](https://github.com/your-username/obsidian-sync/issues)
- 📖 [Read the documentation](https://github.com/your-username/obsidian-sync/wiki)

---

**Happy note-taking! 📝✨**