# AgentsView Service Module

NUC-hosted shared AgentsView dashboard backed by PostgreSQL.

## Quick Facts

- **Access URL:** `https://agentsview.cinnamon-rooster.ts.net`
- **Backend:** `agentsview pg serve` on `127.0.0.1:8087`
- **Tailscale Service:** `svc:agentsview` on `tcp:443`
- **Database:** local PostgreSQL database `agentsview`
- **Runtime user:** system user/group `agentsview`
- **Config/token file:** `/var/lib/agentsview/.agentsview/config.toml`
- **1Password token:** `op://Agents/AgentsView/password`

## Architecture

```text
Browser
  -> https://agentsview.cinnamon-rooster.ts.net
  -> Tailscale Service svc:agentsview tcp:443
  -> http://localhost:8087 on nuc
  -> agentsview pg serve
  -> local PostgreSQL database agentsview
```

AgentsView PostgreSQL sync is one-way: local SQLite/session files are pushed into PostgreSQL. The NUC service only serves the shared read-only PG dashboard.

## Systemd Units

| Unit                                 | Purpose                          |
| ------------------------------------ | -------------------------------- |
| `agentsview-pg.service`              | Runs `agentsview pg serve`       |
| `agentsview-tailscale-serve.service` | Configures Tailscale HTTPS proxy |

## Module Files

- `modules/services/agentsview/default.nix` — module definition
- `hosts/nuc/default.nix` — enables `modules.services.agentsview`
- `modules/services/gatus/default.nix` — monitors local backend
- `modules/services/homepage.nix` — dashboard card

## Tailscale Service Setup

Do **not** use manual admin-console approval as the source of truth. Tailscale service definitions and ACL grants live in `~/src/personal/tailnet`.

For new/changed services:

1. Edit `~/src/personal/tailnet/tailscale/policy.hujson` and add the service to the explicit `grants[].dst` service list.
2. Create/update the VIP service with the Tailscale API:
   ```bash
   cd ~/src/personal/tailnet/tailscale
   direnv exec . bash -lc '
     KEY="$TF_VAR_tailscale_api_key"
     curl -fsS -X PUT -u "$KEY:" \
       -H "Content-Type: application/json" \
       -d "{\"name\":\"svc:agentsview\",\"comment\":\"AgentsView dashboard\",\"ports\":[\"tcp:443\"],\"tags\":[\"tag:server\"]}" \
       "https://api.tailscale.com/api/v2/tailnet/-/vip-services/svc:agentsview"
   '
   ```
3. If updating an existing VIP service, include its two existing `addrs` in the PUT body; the API returns `400` without them.
4. Apply ACL:
   ```bash
   cd ~/src/personal/tailnet/tailscale
   direnv exec . tofu apply -auto-approve
   ```
5. Verify host approval:
   ```bash
   curl -fsS -u "$TF_VAR_tailscale_api_key:" \
     https://api.tailscale.com/api/v2/tailnet/-/vip-services/svc:agentsview/devices | jq .
   ```
   Expected: `approvalLevel` is `approved:auto` and `configured` is `ready`.

## Auth Token

AgentsView requires an app-level bearer token in addition to Tailscale access. The token is generated by `agentsview-pg.service` and preserved across restarts.

Retrieve from 1Password:

```bash
op read op://Agents/AgentsView/password
```

Retrieve from NUC if needed:

```bash
ssh nuc 'grep "^auth_token" /var/lib/agentsview/.agentsview/config.toml'
```

## Syncing Sessions

Each machine that creates sessions must push its own local data. For now, avoid exposing PostgreSQL on Tailscale; use an SSH tunnel to the NUC if pushing from another machine.

Example workflow:

```bash
ssh -N -L 15432:/run/postgresql/.s.PGSQL.5432 nuc
# in another shell, configure AgentsView PG URL for localhost tunnel, then:
agentsview pg push --full --all-projects
```

Exact workstation automation is follow-up work tracked in Beads.

## Troubleshooting

```bash
ssh nuc 'systemctl status agentsview-pg --no-pager'
ssh nuc 'journalctl -u agentsview-pg -n 100 --no-pager'
ssh nuc 'systemctl status agentsview-tailscale-serve --no-pager'
ssh nuc 'tailscale serve status --json | jq .Services."svc:agentsview"'
```

If the page loads but asks for authentication, Tailscale is working; paste the token from `op://Agents/AgentsView/password`.

If Tailscale says approval is required, check the tailnet repo/API state before using the admin console manually.
