Bliki Phase 2: Git-Based Filesystem

Phase 2 transformed Bliki from a local static site generator into a git-powered collaborative platform. The working directory became the repository itself — every save is a commit, every webhook triggers a rebuild.

Design Phase

The phase began with extensive design discussions captured in docs/phase2-discussion.md. The core question: how should multiple sources (CLI users, web editors, remote repos) converge on a single working directory?

Key decisions:

The design settled on four interacting components: go-git operations, a webhook handler, file locking, and a watch-rebuild loop.

go-git Integration

github.com/go-git/go-git/v5 became the foundation for all git operations. The internal/git/ package provides:

SSH key authentication was a significant addition. The system detects whether a remote uses SSH or HTTPS, persists the auth type in .bliki/auth-type, and uses SSH key files for authentication. This enables --git-remote-url ssh://git@... workflows.

Consolidation: The Build Command

The most visible change was command consolidation. Phase 1 had separate clone and serve commands. Phase 2 merged them into the single build command with flags:

bliki build --git-remote-url <url>   # clone + build
bliki build --serve                   # build + start server
bliki build --git-remote-url <url> --serve --watch   # all-in-one

This eliminated the CLI/serve disconnect — one command handles everything. The --git-remote-url flag triggers cloning with optional scaffolding of default files.

Design decision: Removed pull, push, and sync commands. The CLI and server communicate with the remote independently through git. No direct CLI-to-server communication is needed.

Config Centralization

Phase 2 introduced a shared viper instance across all packages. Previously, each command created its own viper instance, leading to configuration mismatches.

The centralized approach means:

CLI flag refactoring renamed flags for consistency:

Webhook Handler

The webhook endpoint (POST /api/receive) receives push events from git hosting services:

  1. Validate HMAC-SHA256 signature using webhook_secret config
  2. Fetch latest changes from remote via go-git
  3. Reset working directory to origin/<git_default_branch>
  4. Rebuild if files changed

The webhook supports Forgejo's HMAC-SHA256 signature format. A configurable webhook_secret (env: BLIKI_WEBHOOK_SECRET) authenticates incoming requests.

Config-driven default branch means the reset target is git_default_branch from bliki.toml (default: main), not hardcoded to main.

Watch Mode

The --watch flag enables file watching with auto-rebuild:

An earlier implementation had a bug where the event channel was shadowed, causing rebuilds to not trigger. The fix simplified the architecture: a single loop with inline debounce instead of a channel-based event queue.

Docker & CI

Phase 2 added production deployment support:

Known Limitations

Phase 2 left a few design challenges for future iterations:

What's Next

Phase 2 delivered a git-native workflow: clone a remote, edit content via the web or CLI, and have everything synchronize through git. Phase 3 added user authentication and the inline web editor with real-time rebuild notifications.