# Understanding the AgentsView Daemon Runtime Record: Purpose and Implementation

> Discover the purpose of the AgentsView daemon runtime record. This JSON file tracks PID, network endpoint, and timestamps for secure CLI management of the HTTP server.

- Repository: [Kenn Software/agentsview](https://github.com/kenn-io/agentsview)
- Tags: deep-dive
- Published: 2026-06-20

---

**The daemon runtime record is a JSON metadata file that stores the AgentsView daemon’s PID, network endpoint, service identity, and process timestamps, enabling CLI commands to discover, authenticate, and safely manage the running HTTP server.**

AgentsView runs as a persistent HTTP daemon that serves SQLite-backed session data. To coordinate between the background server process and command-line tooling, the repository implements a **daemon runtime record**—a file-based registry written to the data directory (by default `$XDG_DATA_HOME/agentsview`). This record acts as the single source of truth for process discovery, mode negotiation, and safe lifecycle management across all AgentsView components.

## What the Daemon Runtime Record Contains

The runtime record is a JSON file containing structured metadata about the active daemon process. According to the source code in [`cmd/agentsview/daemon_runtime.go`](https://github.com/kenn-io/agentsview/blob/main/cmd/agentsview/daemon_runtime.go), each record tracks:

- **PID**: The process ID of the running daemon
- **Network endpoint**: The host and port where the HTTP server listens
- **Service name**: Identifies this as an *agentsview* service (distinguishing it from other potential daemons)
- **Version**: The software version running
- **Metadata map**: Extended attributes including host, port, read-only flags, optional Caddy child PID, and process-creation timestamps

When the server starts via `daemon.Listen()` in [`internal/server/server.go`](https://github.com/kenn-io/agentsview/blob/main/internal/server/server.go) (lines 798–809), it automatically writes this record using the `WithRuntimeStore` option. The record persists until graceful shutdown, when `RemoveDaemonRuntime` (lines 95–100) cleans it up.

## How the CLI Discovers Running Daemons

Most AgentsView CLI commands rely on the `FindDaemonRuntime` function (lines 18–44 in [`cmd/agentsview/daemon_runtime.go`](https://github.com/kenn-io/agentsview/blob/main/cmd/agentsview/daemon_runtime.go)) to locate an active daemon before executing operations. This discovery process follows a specific verification chain:

1. **Scan**: List all records in the runtime store directory
2. **Filter**: Select only records matching the *agentsview* service name
3. **Verify**: Check that the recorded PID is still alive using `daemon.ProcessAlive()`
4. **Probe**: Send a ping request to the recorded endpoint to confirm responsiveness
5. **Select**: Prefer the first **writable** daemon found; fall back to a read-only *pg-serve* instance if no writable daemon responds

This ensures that CLI commands always communicate with a valid, active process rather than stale data from a crashed daemon.

## Write-Only vs Read-Only Mode Detection

The runtime record distinguishes between writable SQLite archives and read-only *pg-serve* instances through the `runtimeReadOnly` metadata key. When `WriteDaemonRuntime` creates the record (lines 50–63), it sets:

- `ReadOnly: false` for standard AgentsView daemons serving writable SQLite databases
- `ReadOnly: true` for *pg-serve* read-only instances

During discovery, `daemonRuntimeFromRecord` (lines 98–122) parses this flag to determine transport selection. A writable daemon supports direct HTTP operations, while a read-only daemon triggers transport-layer protections that prevent write attempts. This mode negotiation ensures data consistency by blocking mutations against snapshot or replica instances.

## Preventing PID Reuse Attacks

One critical safety feature involves **process-identity verification** to prevent terminating the wrong process when stopping a daemon. The runtime record stores a `runtimeCreateTime` timestamp (lines 64–70 in `WriteDaemonRuntime`) representing when the daemon process started.

When executing `serve stop`, the `stopTargetConfirmed` function (lines 109–117 in [`cmd/agentsview/serve_lifecycle.go`](https://github.com/kenn-io/agentsview/blob/main/cmd/agentsview/serve_lifecycle.go)) compares the recorded creation time against the current process’s actual creation time. If the PID has been reused by a different process (indicating the original daemon crashed and a new unrelated process claimed the PID), the timestamps will mismatch, and the stop operation aborts. This prevents accidentally killing arbitrary system processes.

## Server Lifecycle Integration

The runtime record integrates directly with the server lifecycle through the `daemon` package. When `ListenAndServe` initializes in [`internal/server/server.go`](https://github.com/kenn-io/agentsview/blob/main/internal/server/server.go), it passes `daemon.WithRuntimeStore()` to register the runtime record automatically:

```go
// internal/server/server.go – ListenAndServe
ln, err := daemon.Listen(
    listenCtx,
    daemon.Endpoint{
        Network: daemon.NetworkTCP,
        Address: addr,
    },
    daemon.WithRuntimeStore(daemon.RuntimeStore{Dir: s.dataDir}), // ← writes the record
)

```

This registration happens atomically with socket binding, ensuring the record only exists while the server is actually listening. The `RemoveDaemonRuntime` function handles cleanup during graceful shutdown, preventing orphaned records that could mislead future discovery attempts.

## Legacy Migration Support

Older versions of AgentsView stored daemon state in JSON files named `server.<port>.json`. The current implementation maintains backward compatibility through `migrateLegacyDaemonRuntimes` (lines 82–115 in [`cmd/agentsview/daemon_runtime.go`](https://github.com/kenn-io/agentsview/blob/main/cmd/agentsview/daemon_runtime.go)). On startup, this function scans for legacy state files and converts them into the modern runtime record format, preserving existing user configurations without manual intervention.

## Summary

- **Discovery**: The `FindDaemonRuntime` function uses the record to locate active daemons by verifying PID liveness and ping responsiveness.
- **Safety**: Process-creation timestamps in `runtimeCreateTime` prevent PID reuse attacks during daemon shutdown.
- **Mode Selection**: The `runtimeReadOnly` flag distinguishes between writable SQLite daemons and read-only *pg-serve* instances.
- **Lifecycle**: Automatic registration via `daemon.Listen()` and cleanup via `RemoveDaemonRuntime` maintain record accuracy.
- **Compatibility**: Legacy `server.<port>.json` files are automatically migrated to the current runtime record format.

## Frequently Asked Questions

### Where is the daemon runtime record stored?

By default, AgentsView writes the runtime record to `$XDG_DATA_HOME/agentsview` (typically `~/.local/share/agentsview` on Linux systems). The specific filename is managed by the `daemon.RuntimeStore` abstraction, which handles JSON serialization and directory scanning.

### How does AgentsView prevent stopping the wrong process?

The `stopTargetConfirmed` function in [`cmd/agentsview/serve_lifecycle.go`](https://github.com/kenn-io/agentsview/blob/main/cmd/agentsview/serve_lifecycle.go) verifies process identity by comparing the `runtimeCreateTime` stored in the record against the actual creation time of the process with the recorded PID. If the timestamps differ, the system assumes PID reuse has occurred and aborts the stop operation to prevent terminating an unrelated process.

### What is the difference between writable and read-only daemon records?

Writable records (`ReadOnly: false`) represent standard AgentsView daemons serving mutable SQLite databases, allowing full CRUD operations. Read-only records (`runtimeReadOnly: true`) indicate *pg-serve* instances or snapshot daemons where write operations are prohibited. The CLI uses this distinction to select appropriate transport mechanisms and prevent accidental write attempts against read-only archives.

### How does the server register its runtime record on startup?

During initialization, [`internal/server/server.go`](https://github.com/kenn-io/agentsview/blob/main/internal/server/server.go) invokes `daemon.Listen()` with the `WithRuntimeStore()` option, passing the data directory path. This triggers automatic JSON record creation containing the daemon’s PID, endpoint, and metadata. The record remains locked to the process lifecycle and is automatically removed by `RemoveDaemonRuntime` during graceful shutdown.