Skip to main content

AgentSight Data and Storage

Everything AgentSight captures stays on the host in SQLite databases. The Dashboard, the CLI, and the HTTP API are three views over the same files.

Where the data lives​

All databases sit in /var/log/sysak/.agentsight/, created with a private umask so only root can read them.

FileContent
genai_events.dbThe main store: LLM calls plus periodic CPU/RSS samples for their Agent processes, with timings, session and conversation IDs
agentsight.dbAudit records (LLM calls and process actions) and Token consumption aggregates
interruption_events.dbDetected interruptions with their type, severity, and evidence
optimization.dbResults of Dashboard optimization analyses
trajectories.dbATIF v1.7 trajectories, only when features.trajectory_collection is enabled
.agentsight-private/security.dbSecurity events, cases, evidence, and containment state
.agentsight-private/enforcement.dbEnforcement bindings, violations, and transitions
.agentsight-private/reuse.dbTrajectory reuse labels, human decisions, LLM verdicts, and label audit events
.agentsight-private/causal.dbDurable causal-attribution cases
.dashboard_tokenThe Dashboard access token (64 hex characters, root-only)
optimization_config.jsonLLM settings entered on the Dashboard Settings page (API key stored here)
*.db-wal, *.db-shmSQLite write-ahead log and shared memory; normal, and checkpointed on clean shutdown

--db on serve, dashboard, skill-metrics, audit, metrics, summary, and interruption points at a different database file, which is how you browse a copy or an archive. The tracer itself always writes to the default directory.

serve --db <path> resolves every sibling store from the --db directory — GenAI events, the interruption store, the trajectory store, and the health checker all follow it. The private security, enforcement, reuse, and causal stores follow from its .agentsight-private/ subdirectory. So an archived copy is shown in isolation, without mixing in the live host's data. Put the sibling .db files and, when present, .agentsight-private/ directory beside the file you pass. A bare relative --db name.db uses the current directory.

These files contain full prompts and model responses. Treat them as sensitive: keep the directory permissions as installed, and be careful when copying them off the host.

When SQLite is the only active output, completed calls are saved immediately. A registered default Logtail output whose deployment file is missing or telemetry is disabled does not add a session wait. If the Agent's session becomes known later, the stored session ID and full-event JSON are updated together. FFI callbacks and active external exporters keep the existing session-resolution wait before delivering a call. Output gates are checked for each call, so enabling or resuming Logtail restores that wait for subsequent calls.

Retention and size limits​

trajectories.db keeps Hermes scan fingerprints in source_session_states, keyed by collected session ID, source and canonical database path. This metadata survives payload eviction and collector restarts; unchanged sessions stay evicted until the source changes. The table is created and seeded from existing Hermes trajectory metadata on writable open, without reading ATIF payloads. Maintenance removes state when its source-message timestamp expires or its source file disappears. With age retention disabled, state remains while its source database exists. No JSON config version change or source Hermes database modification is required.

When an SSE call exceeds a capture byte limit or is evicted for connection capacity, AgentSight reports bounded metadata with incomplete=true, metadata_only=true and abandon_reason, without bodies, messages or token usage; byte-limit removal also sets truncated=true. Capacity eviction skips in-flight calls active within the last 5 seconds, including request assembly and response waiting. If all entries are protected, the new exchange is rejected with abandon_reason=capacity_rejected. Completed HTTP/1 connections keep a payload-free slot reservation for 5 seconds so their next keep-alive request can reuse it. Active connections and reservations together stay within connection_capacity; new connections may be rejected until a reservation expires. Hard byte limits can still reclaim active entries. A bounded marker suppresses subsequent tail reads from that call, preventing repeated incomplete records and further connection evictions. A new request or HTTP response clears the marker, except a capacity-rejected exchange stays suppressed until a new request arrives. Markers can be displaced by capacity and expire during maintenance after the larger of the configured connection soft timeout, hard timeout, and 60 seconds. Hard-timeout removal still allows a late response to resume as response-only evidence.

Schema v4 gives every AgentSight-owned database a retention_days, max_db_size_mb, and check_interval_secs policy:

StoreDefault policyCleanup coverageConfiguration
agentsight.db30 days, 500 MiB, every 60 secondsFull: audit, Token, HTTP, and consumption historystorage.primary
genai_events.db30 days, 200 MiB, every 60 secondsFull: GenAI events, resource samples, and evaluation runs share this physical targetstorage.genai
interruption_events.db30 days, 100 MiB, every 60 secondsFull interruption historystorage.interruptions
trajectories.db30 days, 500 MiB, every 300 secondsPartial: trajectory payloads are pruned while recent file and Hermes session fingerprints remain protectedstorage.trajectories
optimization.db30 days, 200 MiB, every 300 secondsFull optimization-result historystorage.optimization
.agentsight-private/security.db30 days, 200 MiB, every 3,600 secondsPartial: terminal graphs and unreferenced events are pruned; active case graphs remain protectedstorage.security_audit
.agentsight-private/reuse.db30 days, 200 MiB, every 300 secondsPartial: old label events and unconfirmed, purely automatic labels onlystorage.reuse
.agentsight-private/causal.db30 days, 200 MiB, every 300 secondsPartial: oldest cache entries are evicted, but the latest entry is retainedstorage.causal
.agentsight-private/enforcement.db30 days, 100 MiB, every 60 secondsPartial: violations and terminal transitions onlystorage.enforcement

Tokenless's stats.db is listed by the status API as external. AgentSight opens it read-only and never applies its lifecycle policy; Tokenless remains responsible for that file.

storage.max_total_size_mb adds a combined physical-allocation limit across the nine managed AgentSight databases. It defaults to 2200 MiB, accepts 0 to disable the combined limit, and otherwise must be at least 9 MiB so every database can retain the minimum enforceable allocation.

A zero value disables its corresponding rule: age cleanup, size cleanup, or scheduled checks. An interval of zero therefore disables automatic governance for that store even if its age and size values are non-zero. The old check_interval_inserts key is unsupported; pre-v4 configuration is backed up and replaced through the normal schema upgrade mechanism.

Each existing long-running trace, serve, local trace, or local serve process starts at most one lightweight sqlite-maintenance thread; no separate maintenance process is launched. That thread runs all of its database jobs sequentially. When trace and serve both cover one physical file, they coordinate through <db>.maintenance.lock; the process that acquires the lock performs fresh retention and size measurements before acting.

GenAI maintenance uses a separate connection from capture delivery and queries. Deletion releases the write lock between small batches, and a busy database defers maintenance to the next pass. WAL checkpointing copies frames in passive mode before attempting immediate truncation, so a pinned reader does not make maintenance wait while excluding the capture writer. Maintenance yields before starting another delete batch while capture writes or queued retries need the writer, and resumes on a later scheduled pass.

When periodic maintenance is enabled, the trace process delegates primary and GenAI WAL checkpoints to that worker instead of triggering them on capture commits. Passive checkpoints run about once a second between retention/capacity checks; check_interval_secs still controls cleanup. SQLite's synchronous durability setting is unchanged. Disabling periodic maintenance retains automatic WAL checkpointing on capture connections.

With runtime_limits.cpu_budget_percent enabled, primary and GenAI cleanup yield between bounded operations and continue on later worker ticks. They share CPU admission with capture delivery; retention and capacity targets remain in effect, but a cleanup pass may take longer to finish.

Completed captures that encounter a transient SQLite write lock stay in the existing pending queue for retry. They share pending_genai_max_count and pending_genai_max_bytes_mb with session-ID waits. Retries do not resend records to external sinks. Budget rejection and permanent write failures are logged; agentsight_genai_sqlite_retry_total records queued, busy, stored, over-budget and failed outcomes.

Every pass follows the same lifecycle:

  1. Delete records older than the retention cutoff, subject to the store's schema-safe eligibility rules.
  2. If age deletion changed the database, require a successful WAL checkpoint before continuing.
  3. Trigger capacity pruning only when physical allocation (database, WAL, and SHM) exceeds the limit.
  4. Delete the oldest eligible records and checkpoint between rounds until logical usage reaches 90% of the limit.

The combined-budget ranking also includes WAL and SHM. A WAL-heavy database can therefore rank first for one pass; its maintenance checkpoints before pruning, and subsequent passes rebalance using the new physical allocation.

Automatic maintenance never runs VACUUM. Freed pages remain on the freelist and are reused by future writes, so a large physical file can be healthy when its logical usage is within target. To return disk space to the filesystem, stop the service and run sudo sqlite3 /var/log/sysak/.agentsight/<db> 'VACUUM;' manually during a maintenance window.

The partial stores deliberately preserve durable decisions and control state. Reuse maintenance never deletes human-owned, confirmed, or overridden labels. Enforcement maintenance preserves bindings, pending or indeterminate transitions, and credential intent/snapshot state. Causal entries are caches, so eviction can cause a later request to repeat a billed attribution computation.

For container deployments: retention only matters when the data directory is persistent. Without a volume mount, every container restart wipes all data — see Containers and sidecars.

The Settings page changes the combined limit through POST /api/storage/config. Long-running trace, serve, local trace, and local serve processes started with a configuration file re-read valid edits before maintenance, so no restart is required. Local processes started without --config cannot persist edits. A missing, incomplete, or invalid file leaves the last valid limit active. The page also shows physical and logical usage, cleanup coverage, and maintenance-worker state.

Check current usage from the API:

TOKEN=$(sudo cat /var/log/sysak/.agentsight/.dashboard_token)
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:7396/api/storage/status \
| python3 -m json.tool

The response uses schema version 3. Each store reports availability, size, policy, coverage, and size_state, plus a maintenance object with scheduled, worker_running, worker_heartbeat_unix_ms, last_attempt_unix_ms, last_success_unix_ms, last_result, consecutive_failures, and next_run_unix_ms. Trajectories, security audit, reuse, causal, and enforcement report partial coverage for their protected data. Runtime fields describe only the process serving this response, so an unscheduled trace-owned store does not prove that another trace process is stopped. No database path is returned. Treat within_policy only as a capacity result: worker health comes from the scheduling, heartbeat, attempt, result, and failure fields.

You can also inspect the directory directly:

sudo du -sh /var/log/sysak/.agentsight
sudo ls -la /var/log/sysak/.agentsight

Clearing data​

sudo systemctl stop agentsight.service
sudo rm -rf /var/log/sysak/.agentsight
sudo systemctl start agentsight.service

Removing the directory also removes the Dashboard token, so a new one is generated on the next start. To keep the history instead, copy the directory somewhere safe and browse it later with agentsight serve --db /path/to/genai_events.db.

HTTP API​

The server publishes its own route inventory, so you never have to guess:

curl -s http://127.0.0.1:7396/api/docs | python3 -m json.tool

Requests from anywhere other than loopback need the token:

TOKEN=$(sudo cat /var/log/sysak/.agentsight/.dashboard_token)
curl -s -H "Authorization: Bearer $TOKEN" http://<host>:7396/api/sessions

Endpoint groups in 0.11:

GroupExamplesPurpose
ServiceGET /health, GET /metrics, GET /api/docsLiveness, Prometheus metrics, route list (/health and /metrics are loopback-only)
AuthenticationGET /api/auth/status, GET /api/auth/verify, POST /api/auth/loginAuth state, capability list, token → cookie exchange
Sessions and tracesGET /api/sessions, GET /api/sessions/{id}/traces, GET /api/sessions/{id}/resources, GET /api/traces/{id}, GET /api/conversations/{id}, POST /api/sessions/searchSession list, per-session conversation summaries (keyed by conversation_id) and process resources, per-call detail by response id, semantic search
MetricsGET /api/timeseries, GET /api/metrics/latency, GET /api/agent-namesToken time series, latency percentiles, Agent filter values
InterruptionsGET /api/interruptions, /count, /stats, /session-counts, /conversation-counts, POST /api/interruptions/{id}/resolveTriage and resolution
Agent healthGET /api/agent-health, DELETE /api/agent-health/{pid}, POST /api/agent-health/{pid}/restartLive Agent state and recovery actions
Tokenless recordsPOST /api/tokenless/refresh, GET /api/tokenless/records, GET /api/tokenless/records/{cache_id}Refresh saved statistics, list metadata, and read details; content requires explicit include_content=true. All three routes require Dashboard credentials, including on loopback
Token savingsGET /api/token-savings, GET /api/token-savings/session/{id}Tokenless savings
ATIF exportGET /api/export/atif/session/{id} (also trace and conversation)Trajectory export
TrajectoriesGET /api/trajectories, /filters, /steps, /{session_id}Collected trajectories. The list accepts optional label, exclude_label, and human_backed filters; label is comma-separated effective labels such as good,bad
Reuse labelsPOST /api/reuse/triage, GET /api/reuse/sessions, POST /api/reuse/sessions/{session_id}/label, POST /api/reuse/sessions/labels:batch-confirm, GET /api/reuse/label-stats, POST /api/reuse/judgeRule triage and human label decisions. The judge requires features.reuse_llm_judge=true and configured LLM credentials; it makes billed model calls
PreferencesGET /api/preferences, /export, /turnsUser preference analysis, Markdown export, and source user turns for agent-side reasoning
StorageGET /api/storage/status, POST /api/storage/configSchema-v3 combined limit, capacity, coverage, and maintenance-worker status; POST persists the combined limit when a config file is available
Skill metricsGET /api/skill-metrics, /downloads, /loads, /usage-ratio, /distribution, /hotnessSkill adoption
OptimizationPOST /api/optimize/sessions/{id}/{dimension}, GET /api/optimize/results, GET and POST /api/optimize/configLLM-assisted analysis
Quality and attributionPOST /api/grader/evaluate, GET /api/grader/latest, POST /api/causal-attributionSession quality scoring, root-cause attribution
Security and auditGET /api/security/*, GET /api/audit/*, POST /api/audit/cases/{id}/reviewPresent when agent-sec-core is installed
EnforcementGET /api/enforcement/health, POST /api/enforcement/bindings, GET /api/enforcement/violationsPresent when the enforcer is installed; mutations always require the token

Time ranges are nanosecond epochs (start_ns, end_ns), matching the CLI's --last window.

# last hour of sessions
NOW=$(date +%s%N); AGO=$((NOW - 3600000000000))
curl -s "http://127.0.0.1:7396/api/sessions?start_ns=$AGO&end_ns=$NOW" | python3 -m json.tool | head

Fetch the raw CPU/RSS points and activity intervals for one Session:

curl -s "http://127.0.0.1:7396/api/sessions/<SESSION_ID>/resources?max_points=2000" | python3 -m json.tool

Each sample is process-level and contains an epoch-nanosecond timestamp, PID, CPU percentage, and resident memory in bytes. For a multi-process Agent, the Dashboard sums the PIDs associated with the Session. This is execution-context data rather than strict per-Session attribution: a shared Agent process can serve more than one Session at the same time. LLM intervals use captured request and response timestamps; a Tool Call interval is inferred from the LLM response that requested the tool to the next LLM request carrying the matching tool result. Gaps not covered by an LLM call or a matched Tool Call are returned as idle; unmatched Tool Calls are not assigned a fabricated end timestamp.

Process output in Chrome traces​

For an aggregated process lifecycle, Chrome Trace output retains the beginning of stdout and stderr, at most 64 KiB per stream. Once a stream reaches that limit, its later output is omitted; the other stream can continue up to its own limit. If the limit cuts through a UTF-8 character, the incomplete tail is omitted. Other invalid bytes use lossy text decoding.

Prometheus metrics​

curl -s http://127.0.0.1:7396/metrics | head
# HELP agentsight_token_input_total Total input tokens consumed by agent (all-time)
# TYPE agentsight_token_input_total counter
agentsight_token_input_total{agent="CoshNG"} 100000
agentsight_token_input_total{agent="Cosh"} 50000

Counters are per Agent and all-time: agentsight_token_input_total, agentsight_token_output_total, agentsight_token_total_total, agentsight_llm_requests_total. /metrics is loopback-only, so scrape it with a node-local Prometheus agent or expose it through a local reverse proxy. agentsight metrics prints the same content from the CLI.

agentsight_http_sse_discarded_bytes_total{reason} counts tail bytes skipped while an abandoned SSE marker is retained. Compare it with agentsight_http_conn_removed_total{reason,state} to distinguish resource pressure from normal completion. Aggregator stage timings include compact SSE reads. agentsight_http2_closed_stream_discarded_bytes_total counts DATA payload bytes skipped after HTTP/2 completion or resource/protocol abandonment; trailers still update the header decoder.

Trajectory export (ATIF v1.7)​

Any session, conversation, or single trace exports as a self-contained JSON trajectory — Agent metadata, steps, messages, tool calls, and Token totals:

curl -s http://127.0.0.1:7396/api/export/atif/session/<SESSION_ID> > session.atif.json

The Dashboard's Trajectory Viewer offers the same file through Download JSON, and can re-import one captured on another host. Use it for offline analysis, sharing a reproduction, or feeding evaluation pipelines.

External log export​

AgentSight can write structured events to a file for an external log collector to pick up:

{
"runtime": { "sls_logtail_path": "/var/log/anolisa/agentsight/events.jsonl" },
"features": { "sls_logtail": true }
}

The path can be changed while AgentSight runs — set it to "" to pause export. Leave both settings at their defaults if you want the data to stay entirely local. Collector-side configuration (endpoints, credentials) is out of scope for AgentSight.

Backup​

sudo systemctl stop agentsight.service
sudo tar czf agentsight-data-$(date +%F).tar.gz -C /var/log/sysak .agentsight
sudo systemctl start agentsight.service

Stopping the service first ensures the WAL is checkpointed, so the archive is consistent.

Queried Tokenless statistics are saved in genai_events.db alongside the existing GenAI store. Repeating a query replaces metadata for the same endpoint, source ID and original timestamp, preserving explicitly fetched content. Original source session IDs are retained. These copies follow storage.genai age and capacity cleanup; they do not modify Tokenless's database.