TazPod: Sync Daemon Detail

Level 3 (Detail) — Background auto-save and push cycle.

Concept

The sync daemon runs as __internal_sync_daemon — a background process spawned by tazpod up. Every 5 minutes it saves the RAM vault to disk and pushes the encrypted archive to S3.

Startup

File: cmd/tazpod/lifecycle.goup() (line 14)

exec.Command("tazpod", "__internal_sync_daemon").Start()

Spawned as a detached process by up(). The daemon shares the same tazpod binary and the same config.

Cycle

File: cmd/tazpod/sync.gosyncDaemon() (lines 14-56)

[Start] ──► log: /tmp/tazpod-sync.log ──► ticker: 5 min
                                        │
                              ┌─────────┴──────────┐
                              ▼                    ▼
                         vault unlocked?      skip cycle
                              │
                              ▼
                    vault.Save("") ──► re-encrypt RAM to disk
                              │
                              ▼
                    pushVaultInternal() ──► upload to S3
                              │
                              ▼
                    log result ──► wait 5 min ──► loop

Unlock detection

func isVaultUnlocked() bool {
    if !utils.IsMounted(vault.MountPath) { return false }
    _, err := os.Stat(vault.PassCache)
    return err == nil
}

Checks both that the tmpfs is mounted AND that the passphrase cache file exists. If the vault is locked, the daemon logs a skip and continues.

Graceful Shutdown

The daemon uses signal.NotifyContext for SIGTERM and SIGINT:

ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)

On signal, the current cycle completes and the daemon exits cleanly.

Log Path

/tmp/tazpod-sync.log

Uses slog with a text handler writing to the log file. Each cycle logs:

  • “Starting sync cycle”
  • On success: “Sync completed” with elapsed time
  • On failure: “Sync failed” with error

No History From Daemon

Il daemon sincronizza solo il latest vault.tar.aes. Le history copies su S3 sono create solo dal comando manuale tazpod push vault. Il daemon non ha accesso al content hash del plaintext e non produce versioni storiche.

Failure Model

  • If S3 upload fails → error is logged, daemon continues
  • If local save fails → error is logged, daemon continues
  • The vault on local disk is always refreshed before the S3 push
  • Local safety is preserved even if remote sync is broken

Code Paths

FileFunctionLineRole
lifecycle.goup()14Spawns daemon process
sync.gosyncDaemon()14Main loop, logging, ticker
sync.goisVaultUnlocked()58Unlock detection
sync.gopushVaultInternal()119S3 upload

Known Issues

  • TD-022: pushVaultInternal() resolves vault path from cwd, not from canonical workspace root

See Also