How the Auto-Push Daemon Operates as a Background Service in AgentsView

The auto-push daemon is a Go-based background service that continuously mirrors local agent session data to PostgreSQL using file-system monitoring, debounced push cycles, and automatic service integration with systemd or launchd.

The agentsview repository implements a robust synchronization layer that keeps a remote PostgreSQL database in lock-step with local agent session files. The auto-push daemon orchestrates this process through a resilient architecture combining local SQLite caching, file watching, and graceful error recovery.

Architecture Overview

The daemon implementation spans three main components that work together to provide reliable background operation:

Component Role Key Source File
Watch daemon Core loop handling local sync, PG pushes, and file change reactions runPGPushWatch in [cmd/agentsview/pg_watch.go](https://github.com/kenn-io/agentsview/blob/main/cmd/agentsview/pg_watch.go)
Push loop Debounced and periodic trigger logic newPushLoop in [cmd/agentsview/pg_watch_loop.go](https://github.com/kenn-io/agentsview/blob/main/cmd/agentsview/pg_watch_loop.go)
Service wrapper Registers the daemon with the host init system pg_service.go with platform-specific managers (pg_service_systemd.go, pg_service_launchd.go, pg_service_manager.go)

Daemon Initialization and Startup

When started via agentsview pg push --watch, the daemon executes a strict initialization sequence to ensure safe, single-instance operation.

Configuration Loading and Environment Setup

The daemon begins by loading a minimal configuration and preparing the runtime environment:

appCfg, err := config.LoadMinimal()
...
if err := os.MkdirAll(appCfg.DataDir, 0o755); err != nil { … }
setupLogFileNamed(appCfg.DataDir, "pg-watch.log")

The config.LoadMinimal() function (from [internal/config/config.go](https://github.com/kenn-io/agentsview/blob/main/internal/config/config.go)) loads only the settings required for pushing, including the data directory and PostgreSQL URL. The daemon creates a dedicated log file at pg-watch.log within the data directory for persistent logging during service operation.

Target Resolution and Validation

pgCfg, projects, exclude, err := resolveWatchTargets(appCfg, cfg)

The resolveWatchTargets function validates the PostgreSQL configuration and expands any --project or --exclude filters provided via command-line arguments.

Single-Instance Guard

To prevent duplicate daemon processes, the implementation uses a file-based lock:

lockPath, _ := (daemon.RuntimeStore{Dir: appCfg.DataDir, Prefix: "pg-watch"}).LockPath()
lock := flock.New(lockPath)
locked, err := lock.TryLock()
...
defer lock.Unlock()

The [internal/daemon/runtime.go](https://github.com/kenn-io/agentsview/blob/main/internal/daemon/runtime.go) helper generates a lock path under the data directory. If the lock cannot be acquired, the program exits immediately, ensuring only one watcher per machine runs at a time.

Sync Engine Initialization

engine := sync.NewEngine(database, sync.EngineConfig{
    AgentDirs:               appCfg.AgentDirs,
    Machine:                 "local",
    BlockedResultCategories: appCfg.ResultContentBlockedCategories,
})

The sync.Engine (from [internal/sync/engine.go](https://github.com/kenn-io/agentsview/blob/main/internal/sync/engine.go)) reads agent session files, applies classifier configuration, and writes results into the local SQLite store.

Initial Synchronization

didResync := cfg.Full || database.NeedsResync()
if didResync {
    engine.ResyncAll(ctx, nil)   // full rebuild when needed
} else {
    engine.SyncAll(ctx, nil)     // incremental sync
}

On startup, the daemon performs either a full resync (when schema changes or the --full flag is present) or an incremental sync, ensuring the local database reflects the current state of disk before any pushing begins.

The Push Loop and File Watching Mechanism

After initialization, the daemon enters its main operational loop, combining reactive file watching with periodic safety checks.

The pgPusher Helper

The pgPusher struct encapsulates the push cycle:

type pgPusher struct {
    localSync func(context.Context) error
    connect   func() (pgTarget, error)
    target    pgTarget
}

The pgPusher.push method performs a single cycle: local sync → ensure PostgreSQL schema → push data → error handling. The connect closure lazily creates a postgres.Sync object (from [internal/postgres/push.go](https://github.com/kenn-io/agentsview/blob/main/internal/postgres/push.go)) only when needed, and the reset method discards broken connections for automatic recovery.

Debounced Push Loop

loop, ticker := newPushLoop(debounce, interval,
    func(c context.Context, r pushReason) error { return pusher.push(c, r, false) })
defer ticker.Stop()

The newPushLoop function in pg_watch_loop.go returns a pushLoop struct that manages two timing mechanisms:

  • Debounce timer (default 30 seconds): Delays pushes when file changes occur in rapid succession.
  • Floor ticker (default 15 minutes): Guarantees a minimum push frequency even during idle periods.

File Watcher Integration

stopWatcher, unwatchedDirs := startFileWatcher(appCfg, engine,
    func(paths []string) {
        engine.SyncPaths(paths)   // fast sync of only the changed files
        loop.NotifyDirty()        // tell the push loop "something changed"
    })
defer stopWatcher()

The file watcher monitors configured agent directories. When changes are detected, it performs a fast sync of only the affected paths via engine.SyncPaths, then notifies the push loop via NotifyDirty(). If permission limits prevent watching certain directories, the daemon falls back to the periodic floor tick for eventual consistency.

Graceful Shutdown Handling

loop.Run(ctx)   // blocks until the context is cancelled (SIGINT/SIGTERM)

The Run method blocks the main goroutine, listening for the debounce timer, floor ticker, and cancellation signals. On termination (Ctrl-C or systemd stop), the lock is released and database connections close cleanly.

Installing as a System Service

For production deployments, agentsview provides a service wrapper that registers the daemon with the host's init system.

Service Installation

The agentsview pg service install command creates platform-specific unit files that execute the same binary with the arguments pg push --watch.

Systemd implementation (pg_service_systemd.go):

[Unit]
Description=agentsview PostgreSQL auto-push
After=network.target

[Service]
ExecStart=/usr/local/bin/agentsview pg push --watch
Restart=on-failure
StandardOutput=append:/var/lib/agentsview/pg-watch.log
StandardError=inherit

Launchd implementation (pg_service_launchd.go) creates an equivalent plist for macOS systems.

The generic manager (pg_service_manager.go) abstracts install, start, stop, status, and log operations, allowing the CLI to remain agnostic to the underlying init system.

Practical Usage Examples

Run the Daemon Manually (Debugging Mode)

$ agentsview pg push --watch
agentsview pg watch: pushing to PostgreSQL as "my-machine" (debounce 30s, floor 15m)

# Logs appear on STDOUT and in $AGENTSVIEW_DATA_DIR/pg-watch.log

Install as a System Service

$ agentsview pg service install
Installed service unit at /etc/systemd/system/agentsview-pg-watch.service
Service installed and started.
View logs with: agentsview pg service logs -f

Check Service Status

$ agentsview pg service status
● agentsview-pg-watch.service - agentsview PostgreSQL auto-push
   Loaded: loaded (/etc/systemd/system/agentsview-pg-watch.service; enabled)
   Active: active (running) since Tue 2024-04-02 …
Last push: 2024-04-02T12:34:56Z

Follow Live Logs

$ agentsview pg service logs -f
2024/04/02 12:34:56 pg watch: starting (machine="my-machine" debounce=30s interval=15m)
2024/04/02 12:35:00 pg watch: pushed 12 sessions, 34 messages (startup)

Stop and Uninstall

$ agentsview pg service stop
$ agentsview pg service uninstall
Removed service unit at /etc/systemd/system/agentsview-pg-watch.service

Summary

  • Single-instance guarantee: The daemon uses file locking (flock) via daemon.RuntimeStore to prevent multiple concurrent instances.
  • Debounced push loop: Combines a 30-second debounce timer for rapid changes with a 15-minute floor ticker to ensure data consistency.
  • Efficient file watching: Monitors agent directories and performs incremental syncs (engine.SyncPaths) only on changed files.
  • Service integration: Native systemd and launchd support through pg_service_systemd.go and pg_service_launchd.go, enabling automatic startup and restart policies.
  • Resilient error handling: The pgPusher resets connections automatically, allowing recovery from temporary PostgreSQL outages without manual intervention.

Frequently Asked Questions

What triggers the auto-push daemon to send data to PostgreSQL?

The daemon pushes data based on two triggers: file system events (debounced at 30 seconds) and a periodic floor ticker (every 15 minutes). When the file watcher detects changes in monitored agent directories, it calls loop.NotifyDirty(), which schedules a push after the debounce period expires. The floor ticker ensures a push occurs even if no file events are detected, providing a safety net for data consistency.

How does the daemon prevent multiple instances from running simultaneously?

The daemon implements a single-instance guard using the flock library. During startup, it attempts to acquire a lock on a file created via daemon.RuntimeStore{Dir: appCfg.DataDir, Prefix: "pg-watch"}.LockPath(). If another instance holds the lock, TryLock() fails and the program exits immediately, ensuring only one watcher process runs per machine.

What happens if the PostgreSQL connection fails during operation?

The pgPusher struct handles connection failures gracefully. If a push operation fails, the reset method closes and discards the broken connection. The daemon then relies on the push loop's retry logic, which attempts to reconnect on the next iteration (triggered by either the debounce timer or floor ticker). This design allows automatic recovery from temporary network issues or PostgreSQL restarts without requiring manual intervention.

Can I run the auto-push daemon without installing it as a system service?

Yes. The daemon can run interactively using the agentsview pg push --watch command. This mode is useful for debugging, development, or temporary synchronization tasks. When run manually, the daemon still creates the pg-watch.log file in the data directory and respects all configuration flags, but it does not register with systemd or launchd and will terminate when the terminal session ends or receives SIGINT.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →