Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ jobs:
uv run ruff check .
uv run ruff format --check .

- name: Lint Markdown
run: npx --yes markdownlint-cli "**/*.md" --ignore ".venv"

- name: Type check with Mypy
run: uv run mypy .

Expand Down
49 changes: 49 additions & 0 deletions .markdownlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# .markdownlint.yaml

# Inherit default rules
default: true

# --- Disabled Rules ---

# MD013: Line length
# Rationale: Hard-wrapping text disrupts IDE reading flow, breaks URLs, and creates arbitrary diff churn.
MD013: false

# MD033: Inline HTML
# Rationale: Required for layout elements unsupported by strict Markdown (e.g., <details> blocks, complex tables).
MD033: false

# --- Refined Rules ---

# MD024: Multiple headings with the same content
# Rationale: Allows duplicate subheadings (e.g., "Parameters") under different primary function headings.
MD024:
siblings_only: true

# --- AST/Parser Enforcement ---

# MD031: Fenced code blocks should be surrounded by blank lines
# Rationale: Prevents strict parsers from rendering backticks as raw text instead of <pre><code> blocks.
MD031: true

# MD032: Lists should be surrounded by blank lines
# Rationale: Prevents contiguous text from merging into lists, ensuring correct AST generation.
MD032: true

# --- Structural Consistency ---

# MD003: Heading style
# Rationale: Enforces ATX style (# Heading) exclusively.
MD003:
style: "atx"

# MD004: Unordered list style
# Rationale: Enforces dash markers for consistency across the syntax tree.
MD004:
style: "dash"

# MD009: Trailing spaces
# Rationale: Allows exactly two spaces for hard line breaks; flags arbitrary whitespace.
MD009:
br_spaces: 2
strict: false
7 changes: 7 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,10 @@ repos:
rev: v1.19.1
hooks:
- id: mypy

# 3. Markdown linting
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.47.0
hooks:
- id: markdownlint
args: ["--fix"] # Automatically resolves formatting deviations
10 changes: 5 additions & 5 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ diverse, inclusive, and healthy community.
Examples of behavior that contributes to a positive environment for our
community include:

* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
- Focusing on what is best not just for us as individuals, but for the
overall community

## Enforcement
Expand Down
9 changes: 9 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ First off, thanks for taking the time to contribute! 🎉
## How to Contribute

### Reporting Bugs

1. Check if the issue has already been reported.
2. Open a new issue with a clear title and description.
3. Include relevant logs (`git-pulsar log`) or reproduction steps.
Expand All @@ -15,25 +16,29 @@ This project uses [uv](https://github.com/astral-sh/uv) for dependency managemen

1. **Fork & Clone**
Fork the repo and clone it locally:

```bash
git clone https://github.com/jacksonfergusondev/git-pulsar.git
cd git-pulsar
```

2. **Environment Setup**
We use `uv` to manage the virtual environment and dependencies.

```bash
# Creates .venv and installs dependencies (including dev groups)
uv sync
```

*Optional: If you use `direnv`, allow the automatically generated configuration:*

```bash
direnv allow
```

3. **Install Hooks**
Set up pre-commit hooks to handle linting (Ruff) and type checking (Mypy) automatically.

```bash
pre-commit install
```
Expand All @@ -49,6 +54,7 @@ uv run pytest
### Pull Requests

1. **Create a Branch**

```bash
git checkout -b feature/my-amazing-feature
```
Expand All @@ -58,13 +64,16 @@ uv run pytest

3. **Verify**
Ensure your code passes the linter and tests locally.

```bash
uv run pytest
```

(Pre-commit will also run `ruff` and `mypy` when you commit).

4. **Commit & Push**
Please use clear commit messages.

```bash
git commit -m "feat: add support for solar flares"
git push origin feature/my-amazing-feature
Expand Down
66 changes: 36 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,35 +36,37 @@ This system is designed to operate safely alongside standard Git commands withou
### 1. Out-of-Band Indexing (The "Shadow" Index)

Most autosave tools aggressively run `git add .`, which destroys the user's carefully staged partial commits.
* **The Invariant:** The user's `.git/index` must never be touched by the daemon.
* **The Implementation:** Pulsar sets the `GIT_INDEX_FILE` environment variable to a temporary location (`.git/pulsar_index`). It constructs the tree object using low-level plumbing commands (`git write-tree`), bypassing the porcelain entirely. This ensures **Zero-Interference** with your active workflow.

- **The Invariant:** The user's `.git/index` must never be touched by the daemon.
- **The Implementation:** Pulsar sets the `GIT_INDEX_FILE` environment variable to a temporary location (`.git/pulsar_index`). It constructs the tree object using low-level plumbing commands (`git write-tree`), bypassing the porcelain entirely. This ensures **Zero-Interference** with your active workflow.

### 2. Distributed State Reconciliation (The "Zipper" Graph)

In a distributed environment (Laptop ↔ Desktop), state drift is inevitable.
* **The Mechanism:** Pulsar maintains a separate refspec for each machine ID.
* **The Topology:** When you run `git pulsar finalize`, the engine performs an **Octopus Merge**, traversing the DAG (Directed Acyclic Graph) of all machine streams and squashing them into a single, clean commit on `main`.

- **The Mechanism:** Pulsar maintains a separate refspec for each machine ID.
- **The Topology:** When you run `git pulsar finalize`, the engine performs an **Octopus Merge**, traversing the DAG (Directed Acyclic Graph) of all machine streams and squashing them into a single, clean commit on `main`.

### 3. Fault Tolerance

* **The Problem:** Laptops die. SSH connections drop.
* **The Solution:** By decoupling commits from pushes, Pulsar can capture local state every few minutes while conserving battery by pushing to the remote at a lower frequency (e.g., hourly). This guarantees that the **Mean Time To Recovery (MTTR)** is minimized regardless of network availability or hardware failure.
- **The Problem:** Laptops die. SSH connections drop.
- **The Solution:** By decoupling commits from pushes, Pulsar can capture local state every few minutes while conserving battery by pushing to the remote at a lower frequency (e.g., hourly). This guarantees that the **Mean Time To Recovery (MTTR)** is minimized regardless of network availability or hardware failure.

---

## ⚡ Features

* **Decoupled Cycles:** Independent intervals for local commits and remote pushes. Save your battery while staying protected.
* **Smart Identity:** Automatically detects naming collisions with other devices on the remote, ensuring unique backup streams for every machine.
* **Roaming Radar:** The background daemon actively polls for topological drift, firing a cross-platform OS notification if another machine leapfrogs your local session so you can `sync` before conflicts arise.
* **Out-of-Band Indexing:** Backups are stored in a configured namespace (default: `refs/heads/wip/pulsar/...`). Your `git status`, `git branch`, and `git log` remain completely clean.
* **Distributed Sessions:** Hop between machines. Pulsar tracks sessions per device and lets you `sync` to pick up exactly where you left off.
* **State-Aware Diagnostics:** The `doctor` command correlates transient log events with active system health to prevent alert fatigue, and proactively scans for pipeline blockers like strict git hooks or broken `systemd` configurations.
* **Zero-Interference:**
* Uses a temporary index so it never messes up your partial `git add`.
* Detects if you are rebasing or merging and waits for you to finish.
* Prevents accidental upload of large binaries (configurable threshold).
* **Cascading Config:** Settings are merged from global defaults, `~/.config/git-pulsar/config.toml`, and local `pulsar.toml` or `pyproject.toml` files.
- **Decoupled Cycles:** Independent intervals for local commits and remote pushes. Save your battery while staying protected.
- **Smart Identity:** Automatically detects naming collisions with other devices on the remote, ensuring unique backup streams for every machine.
- **Roaming Radar:** The background daemon actively polls for topological drift, firing a cross-platform OS notification if another machine leapfrogs your local session so you can `sync` before conflicts arise.
- **Out-of-Band Indexing:** Backups are stored in a configured namespace (default: `refs/heads/wip/pulsar/...`). Your `git status`, `git branch`, and `git log` remain completely clean.
- **Distributed Sessions:** Hop between machines. Pulsar tracks sessions per device and lets you `sync` to pick up exactly where you left off.
- **State-Aware Diagnostics:** The `doctor` command correlates transient log events with active system health to prevent alert fatigue, and proactively scans for pipeline blockers like strict git hooks or broken `systemd` configurations.
- **Zero-Interference:**
- Uses a temporary index so it never messes up your partial `git add`.
- Detects if you are rebasing or merging and waits for you to finish.
- Prevents accidental upload of large binaries (configurable threshold).
- **Cascading Config:** Settings are merged from global defaults, `~/.config/git-pulsar/config.toml`, and local `pulsar.toml` or `pyproject.toml` files.

---

Expand Down Expand Up @@ -104,6 +106,7 @@ Navigate to your project. The first time you run Pulsar, it will register the re
cd ~/University/Astro401
git pulsar
```

*The daemon will now silently snapshot your work based on your configured intervals.*

### 2. Configure Your Intensity
Expand All @@ -124,6 +127,7 @@ You worked on your **Desktop** all night but forgot to push manually. You open y
```bash
git pulsar sync
```

*Pulsar checks the remote, finds the newer session from `desktop`, and fast-forwards your working directory to match it.*

### 4. Restore a File
Expand All @@ -142,6 +146,7 @@ When you are ready to submit or merge to `main`:
```bash
git pulsar finalize
```

*This performs an **Octopus Merge**. It pulls the backup history from your Laptop, Desktop, and Lab PC, squashes them all together, and stages the result on `main`.*

---
Expand All @@ -156,11 +161,11 @@ git pulsar --env

This bootstraps the current directory with:

* **uv:** Initializes a project with fast package management and Python 3.12+ pinning.
- **uv:** Initializes a project with fast package management and Python 3.12+ pinning.

* **direnv:** Creates an .envrc for auto-activating virtual environments and hooking into the shell.
- **direnv:** Creates an .envrc for auto-activating virtual environments and hooking into the shell.

* **VS Code:** Generates a .vscode/settings.json pre-configured to exclude build artifacts and use the local venv.
- **VS Code:** Generates a .vscode/settings.json pre-configured to exclude build artifacts and use the local venv.

---

Expand Down Expand Up @@ -238,28 +243,29 @@ ignore = ["*.tmp", "node_modules/"]

*Focus: Turning the tool from a blind script into a helpful partner that negotiates with you.*

* [ ] **Smart Restore:** Replace hard failures on "dirty" files with a negotiation menu (Overwrite / View Diff / Cancel).
* [ ] **Pre-Flight Checklists:** Display a summary table of incoming changes (machines, timestamps, file counts) before running destructive commands like `finalize`.
* [ ] **Active Doctor:** Upgrade `git pulsar doctor` to not just diagnose issues (like stopped daemons), but offer to auto-fix them interactively.
- [ ] **Smart Restore:** Replace hard failures on "dirty" files with a negotiation menu (Overwrite / View Diff / Cancel).
- [ ] **Pre-Flight Checklists:** Display a summary table of incoming changes (machines, timestamps, file counts) before running destructive commands like `finalize`.
- [ ] **Active Doctor:** Upgrade `git pulsar doctor` to not just diagnose issues (like stopped daemons), but offer to auto-fix them interactively.

### Phase 2: "Deep Thought" (Context & Intelligence)

*Focus: Leveraging data to make the tool feel alive and aware of your workflow.*

* [ ] **Semantic Shadow Logs:** Replace generic "Shadow backup" messages with auto-generated summaries (e.g., `backup: modified daemon.py (+15 lines)`).
* [x] **Roaming Radar:** Proactively detect if a different machine has pushed newer work to the same branch and notify the user to `sync`.
* [ ] **Decaying Retention:** Implement "Grandfather-Father-Son" pruning (keep all hourly backups for 24h, then daily summaries) to balance safety with disk space.
- [ ] **Semantic Shadow Logs:** Replace generic "Shadow backup" messages with auto-generated summaries (e.g., `backup: modified daemon.py (+15 lines)`).
- [x] **Roaming Radar:** Proactively detect if a different machine has pushed newer work to the same branch and notify the user to `sync`.
- [ ] **Decaying Retention:** Implement "Grandfather-Father-Son" pruning (keep all hourly backups for 24h, then daily summaries) to balance safety with disk space.

### Phase 3: The "TUI" Experience (Visuals)

*Focus: Making the invisible backup history tangible and explorable.*
* [ ] **Time Machine UI:** A terminal-based visual browser for `git pulsar restore` that lets you scroll through file history and view side-by-side diffs.
* [ ] **Universal Bootstrap:** Expand `git pulsar --env` to support Linux (apt/dnf) environments alongside macOS.

- [ ] **Time Machine UI:** A terminal-based visual browser for `git pulsar restore` that lets you scroll through file history and view side-by-side diffs.
- [ ] **Universal Bootstrap:** Expand `git pulsar --env` to support Linux (apt/dnf) environments alongside macOS.

### Future Horizons

* [ ] **End-to-End Encryption:** Optional GPG encryption for shadow commits.
* [ ] **Windows Support:** Native support for PowerShell and Task Scheduler.
- [ ] **End-to-End Encryption:** Optional GPG encryption for shadow commits.
- [ ] **Windows Support:** Native support for PowerShell and Task Scheduler.

---

Expand Down
44 changes: 22 additions & 22 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,37 @@ The `src/` directory contains the package source code. The architecture strictly

### 1. The Core Loop (State Management)

* **`git_pulsar/daemon.py`**: The background process.
* **Role:** The "Heartbeat." It wakes up, checks system constraints (Battery, CPU Load), and triggers the backup logic.
* **Logic:** Decouples "Saving" (Commit) from "Publishing" (Push) using independent intervals to optimize for battery life. Incorporates the "Roaming Radar" to poll for remote drift asynchronously.
* **Safety:** Implements `GIT_INDEX_FILE` isolation to ensure it never locks or corrupts the user's active git index.
* **`git_pulsar/ops.py`**: High-level Business Logic.
* **Role:** The "Controller." It orchestrates complex multi-step operations like `finalize` (Octopus Merges), `restore`, and drift detection.
* **Logic:** Calculates the "Zipper Graph" topology to merge shadow commits back into the main branch, and manages atomic file I/O for cross-process state tracking.
* **`git_pulsar/config.py`**: Configuration Engine.
* **Role:** The "Source of Truth."
* **Logic:** Implements a cascading hierarchy (Defaults → Global → Local) to merge settings from `~/.config/git-pulsar/config.toml` and project-level `pulsar.toml` or `pyproject.toml`.
- **`git_pulsar/daemon.py`**: The background process.
- **Role:** The "Heartbeat." It wakes up, checks system constraints (Battery, CPU Load), and triggers the backup logic.
- **Logic:** Decouples "Saving" (Commit) from "Publishing" (Push) using independent intervals to optimize for battery life. Incorporates the "Roaming Radar" to poll for remote drift asynchronously.
- **Safety:** Implements `GIT_INDEX_FILE` isolation to ensure it never locks or corrupts the user's active git index.
- **`git_pulsar/ops.py`**: High-level Business Logic.
- **Role:** The "Controller." It orchestrates complex multi-step operations like `finalize` (Octopus Merges), `restore`, and drift detection.
- **Logic:** Calculates the "Zipper Graph" topology to merge shadow commits back into the main branch, and manages atomic file I/O for cross-process state tracking.
- **`git_pulsar/config.py`**: Configuration Engine.
- **Role:** The "Source of Truth."
- **Logic:** Implements a cascading hierarchy (Defaults → Global → Local) to merge settings from `~/.config/git-pulsar/config.toml` and project-level `pulsar.toml` or `pyproject.toml`.

### 2. The Abstraction Layer (Plumbing)

* **`git_pulsar/git_wrapper.py`**: The Git Interface.
* **Role:** A strict wrapper around `subprocess`.
* **Philosophy:** **No Porcelain.** This module primarily uses git *plumbing* commands (`write-tree`, `commit-tree`, `update-ref`) rather than user-facing commands (`commit`, `add`) to ensure deterministic behavior.
* **`git_pulsar/system.py`**: OS Abstraction.
* **Role:** Identity & Environment.
* **Logic:** Handles the chaos of cross-platform identity (mapping `IOPlatformUUID` on macOS vs `/etc/machine-id` on Linux) to ensure stable "Roaming Profiles."
- **`git_pulsar/git_wrapper.py`**: The Git Interface.
- **Role:** A strict wrapper around `subprocess`.
- **Philosophy:** **No Porcelain.** This module primarily uses git *plumbing* commands (`write-tree`, `commit-tree`, `update-ref`) rather than user-facing commands (`commit`, `add`) to ensure deterministic behavior.
- **`git_pulsar/system.py`**: OS Abstraction.
- **Role:** Identity & Environment.
- **Logic:** Handles the chaos of cross-platform identity (mapping `IOPlatformUUID` on macOS vs `/etc/machine-id` on Linux) to ensure stable "Roaming Profiles."

### 3. Service Management (Lifecycle)

* **`git_pulsar/service.py`**: The Installation Engine.
* **Role:** Interface with the host init system.
* **Logic:** Generates and registers `systemd` user timers (Linux) or instructions for `launchd` (macOS/Homebrew).
- **`git_pulsar/service.py`**: The Installation Engine.
- **Role:** Interface with the host init system.
- **Logic:** Generates and registers `systemd` user timers (Linux) or instructions for `launchd` (macOS/Homebrew).

### 4. The Interface

* **`git_pulsar/cli.py`**: The User Entry Point & Diagnostic Engine.
* **Role:** Argument parsing, UI rendering, and system health evaluation.
* **Logic:** Uses `rich` for terminal visualization. Beyond routing subcommands to `ops.py` and `daemon.py`, it presents the `doctor` diagnostics. It correlates repository state against transient event logs, and relies on `ops.py` to evaluate topological drift across distributed sessions and scan for host-environment pipeline blockers (e.g., strict git hooks, missing `systemd` linger).
- **`git_pulsar/cli.py`**: The User Entry Point & Diagnostic Engine.
- **Role:** Argument parsing, UI rendering, and system health evaluation.
- **Logic:** Uses `rich` for terminal visualization. Beyond routing subcommands to `ops.py` and `daemon.py`, it presents the `doctor` diagnostics. It correlates repository state against transient event logs, and relies on `ops.py` to evaluate topological drift across distributed sessions and scan for host-environment pipeline blockers (e.g., strict git hooks, missing `systemd` linger).

---

Expand Down
Loading