AgentsView

AgentsView indexes coding-agent session transcripts (Claude Code, Codex, Copilot CLI, and others) and reports token usage, cost, and searchable history.

It is local-first: every workstation runs its own copy against its own SQLite archive. This deployment provides a shared aggregation point. Each workstation pushes its sessions into a central PostgreSQL database, and the cluster serves one read-only dashboard over the union of them at https://agentsview.${SECRET_DOMAIN}.

Architecture

workstation A ─ agentsview pg push ─┐
workstation B ─ agentsview pg push ─┼─► datasci16 (PostgreSQL) ◄── agentsview pg serve (this app)
workstation C ─ agentsview pg push β”€β”˜        β–²                              β”‚
                                     datasci-db.${SECRET_DOMAIN}    agentsview.${SECRET_DOMAIN}
                                        (LAN, 10.2.118.7)              (envoy-internal)
  • Sync direction is one-way. Workstations push; nothing flows back. The dashboard is read-only β€” starring and pinning happen locally and travel with the next push.
  • The pod holds no state. pg serve reads everything from PostgreSQL and runs EnsureSchema on startup, so it comes up cleanly against an empty database and needs no PVC or volsync.
  • pg push speaks the PostgreSQL wire protocol, not HTTP. Workstations therefore connect to the database directly, not through the gateway.

Configuration

Setting Value
Image ghcr.io/kenn-io/agentsview
Mode PG_SERVE=1 β†’ entrypoint runs agentsview pg serve
Database agentsview on the datasci16 cluster
Connection string POSTGRES_URL from the database-agentsview secret, templated in db/postgres.yaml to carry sslmode=require
Data dir (AGENTSVIEW_DATA_DIR) /data, an emptyDir β€” holds only config.toml
Ingress envoy-internal, Authelia OIDC via SecurityPolicy

--public-url=https://agentsview.${SECRET_DOMAIN} is not cosmetic. The server validates the Host header on every /api/ request against the addresses it bound to, as DNS-rebinding protection. Requests arriving through Envoy carry the public hostname, so without this flag the UI loads but every API call returns 403.

Client setup

Run this once per workstation.

  1. Read the role and password the operator generated. It is one shared role, so every workstation uses the same credentials:

    kubectl get secret database-agentsview -n datasci -o jsonpath='{.data.POSTGRES_URL}' | base64 -d

    That URL is not usable as-is. Its host is datasci16-rw, the in-cluster service name, which resolves only inside the datasci namespace β€” off-cluster the lookup fails. Take the role and password from it and discard the rest.

  2. Add a [pg] section to ~/.agentsview/config.toml, using the LAN hostname and port:

    [pg]
    url = "postgresql://<role>:<password>@datasci-db.${SECRET_DOMAIN}:5432/agentsview?sslmode=require"

    Append it at the end of the file. A TOML table header captures every key below it, so [pg] placed above existing top-level keys such as auth_token silently reparents them.

    Keep sslmode=require: the client refuses a DSN that permits plaintext to a non-loopback host. machine_name is optional and defaults to the OS hostname; set it only when that hostname is not what you want labelling this machine’s sessions.

    AGENTSVIEW_PG_URL works too if you would rather keep the URL out of the file.

  3. Seed the database, then install the watcher so it stays current:

    agentsview pg push
    agentsview pg service install

    agentsview pg push --watch runs the same loop in the foreground.

Recovering from a schema incompatibility

pg serve migrates the schema forward on startup, but refuses to run against one it considers incompatible β€” most likely after an image bump. It exits with pg serve: schema incompatible and names the fix. There is no reset subcommand; the schema is dropped by hand.

Nothing here is recoverable from PostgreSQL alone, but nothing is lost either: every workstation still holds the authoritative SQLite archive, and a full push rebuilds the hub from them.

  1. Suspend the app so it stops crash-looping into a half-dropped schema:

    flux suspend hr agentsview -n datasci
  2. Drop the schema. It is named agentsview (the [pg] schema default) and holds only pushed data:

    kubectl exec -n datasci "$(kubectl get pods -n datasci -l cnpg.io/instanceRole=primary -o name)" -- psql -d agentsview -c 'DROP SCHEMA IF EXISTS agentsview CASCADE'
  3. Resume. EnsureSchema recreates the tables at the current version on startup:

    flux resume hr agentsview -n datasci
  4. Repopulate from every workstation. --full is required β€” an incremental push would skip sessions it believes are already there:

    agentsview pg push --full

Until each machine has run step 4, the dashboard shows only the machines that have.

Dependencies

  • cnpg-cluster-datasci β€” the datasci16 PostgreSQL cluster
  • ext-postgres-operator-datasci β€” provisions the database and role from the Postgres/PostgresUser CRs in db/
  • envoy-gateway (envoy-internal) and authelia for ingress and login
  • external-secrets β€” pulls the OIDC client secret from datasci.agentsview

Gotchas

  • Every workstation shares one database role. The operator provisions a single owner per database, so pushes are not attributable by credential β€” only by the machine name each client sets.
  • Deletes do not propagate. Removing a session locally leaves it in PostgreSQL; upstream expects manual SQL cleanup.
  • Text search needs nothing. EnsureSchema creates pg_trgm, which is a trusted extension the database owner installs on its own.
  • Bumping the image can require a schema migration. pg serve migrates forward on startup but refuses to run against a schema it considers incompatible; upstream’s answer is to drop and recreate the schema, then re-push from each machine.

References