XO SpaceObservability

Where the data lives

A catalog of portable project records, machine-local history and controls, native agent stores, credentials, and temporary data.

Start with ownership: project records belong with the project; runtime history, local choices, and credentials belong to the installation; native runtimes keep the original conversations. Space reads across these locations to build its views, with selected content copies described below.

The baseline storage catalog describes xo-space 5221119; saved-command behavior is updated against revision 84f0737e23b6bb369fc6b8853afb510a02dd8b21. Paths are defaults, not a scan of your computer. Optional features create their files when used, and older installations can retain the legacy files described below. A runtime or connected service can keep additional data of its own.

Resolve the two roots first

Name used in this guideHow it resolves
Projects rootXO_PROJECTS_ROOT. The local installer uses the directory where you run it; the service's standalone fallback is ~/xo-projects.
State rootQUIRQ_STATE_ROOT. The local installer uses <workspace>/.quirq; the service's standalone fallback is ~/.quirq.
ProjectA project directory inside the projects root. Its .xo/project.json carries its stable identity.
Project runtime keyNormally project.json's pid. Before an identity is available, the service uses a normalized project directory name. This is different from the folder name shown in a URL.
Native homeThe selected runtime's own directory, such as ~/.claude or $CODEX_HOME. It is separate from both roots unless you explicitly configure otherwise.

Setup shows the effective roots. Persisted root changes go into <state root>/roots.env and take effect after a restart. Changing a configured root is not a bulk migration of all files, native homes, credentials, and browser state. The local installer and standalone defaults are defined in install.sh, project_layout.py, and runtime_config.py.

02Three storage locations, three responsibilities
Portable workspace and project recordsStored beside working files
  • <projects root>/.xo/space.json
    Workspace identity.
  • <projects root>/<project>/.xo/
    Project identity, todos, workitems and peer records.
Machine-local Space stateQUIRQ_STATE_ROOT
  • <state root>/projects/<pid>/
    Project history and indexes; keyed by project identity.
  • <state root>/workspace/
    Materialized workspace views and rollups.
  • <state root>/watcher/
    Reading positions, heartbeat and live presence.
  • <state root>/
    Inbox, connections, configuration, credentials and other service records. This directory contains more than disposable caches.
Native and ingestion storesSeparate ownership
  • Agent homes · native databases and logs
    Original conversations and runtime records. Space reads supported data and can retain selected details in its own indexes.
  • Argus store
    Separate Claude Code ingestion database used for aggregate usage.
Illustrative paths. The projects root, state root and native runtime homes can be configured independently. The tables below give the detailed inventory.

Portable project and workspace records

Portable means the record is intended to travel with the project or workspace. It does not mean anonymous, automatically uploaded, or safe to discard. These documents can contain names, descriptions, task text, identities, remote URLs, and paths.

Inside each project

Path relative to the projectData and writer
AGENTS.md, PROJECT.md, OBJECTIVES.md, PLAN.md, PROGRESS.md, memory/, and ordinary output filesHuman- and agent-authored instructions, plans, logs, memory, and deliverables. The scaffold seeds a template; these are content, not inferred telemetry.
.git/Git objects, refs, index, configuration, and commit history, when the project is a repository. Timeline and historical file previews read this history.
.xo/project.jsonStable project pid, owner, creation identity, display metadata, and git provenance. The scaffold and identity service fill their owned fields; the watcher does not use this as a rolling session log.
.xo/agent.jsonOptional adapter-owned attachment: backend, display name, description, creation time, and any adapter-specific fields. Project-bound runtimes create it when an agent is attached. Its presence also informs agent discovery.
.xo/todos.jsonAuthored session steps, runtime/session association, content, description, active form, status, timestamps, and deletion tombstones. The Todo API is the writer.
.xo/workitems.jsonAuthored work and GitHub issue adoption records: title/body, lifecycle, assignee, labels, source reference, linked todo/session IDs, timestamps, and tombstones. The Workitems API owns the record.
.xo/peers.jsonThe human roster: user ID, role, added time, optional endpoint, and label. The Peers API owns it. An empty list represents a solo project.
Other scaffolded .xo/ directoriesReserved project context, memory, state, artifacts, and skills structure. Their presence does not mean the watcher collects or fills them. Inspect the producing feature before interpreting an unfamiliar file.

Keep service-owned .xo records consistent through their APIs. In particular, a runtime's native task tool does not write Space's shared todos. The current contracts are in the project template, identity sink, agent schema, and the todo, workitem, and peer stores.

At the projects root

PathData and writer
<projects root>/.xo/space.jsonThe Space record: identity, owner, label, configured roots, attached backend capabilities, availability, and first/last-use timestamps.
<projects root>/.xo/projects.jsonDirectory registry: project names, stable IDs, scaffold state, and git origin. Refreshed from the actual project directories.
<projects root>/.xo/xo.jsonFrontend manifest: configured feature defaults plus refreshed model/channel status. Written at startup and by status updates.

The filename space.json has two meanings that are easy to confuse: the portable .xo/space.json is the Space record. The HTTP response /xo/space.json is the derived graph, stored as <state root>/workspace/graph.json. See the Space record writer, project registry, frontend manifest, and view paths.

Machine-local project history

The following paths are relative to <state root>/projects/<runtime key>/. They stay outside the portable project tree. Some are replaceable projections; others are accumulated history or local decisions. Treating this entire directory as a disposable cache would lose information.

PathContentsProducing feature
sessions/sessionslist.d/<hash>.jsonOne metadata shard per composite session key: native and application session IDs, backend, directory, timestamps, and adapter-supplied metadata. Directory changes can retain a history of up to 200 entries. The filename hashes the key, not transcript contents.Session index writer, called by adapters and session discovery.
sessions/sessions-augment.jsonPer-session message counts by role, tool-call counts, activity times, authored task counters, and internal task state. Also carries end-time and episode-reference fields when available. Tool-name and usage breakdowns belong in stats or adapter metadata rather than this file.Watcher and Todo API enrichment.
stats.jsonRolling 7-/30-day totals; per-session, per-runtime, per-model, and per-tool breakdowns; file paths/counts, durations, daily tokens/messages/latency, and internal accumulator fields.Watcher stats sink.
timeline.jsonl and timeline.<timestamp>.jsonlNormalized session, file-touch, todo, and workitem lifecycle events. File entries contain project-relative paths; authored work events can contain task/workitem text.Watcher plus explicit Todo/Workitems API actions.
github/issues.jsonGitHub repository reference, fetched issue titles/status/reason/assignees/URLs/timestamps, incremental cursor, fetch time, rate-limit information, and error state.GitHub issue poller; issue actions can update the mirror too.
workitems/claims.jsonWhich runtime/session currently claims a workitem and when that claim began.Workitem claim API; projected against session liveness.
Legacy sessions/sessionslist.json, sessions/sessions.json, other old sessions/ files, sync.json, or activity.jsonCompatibility state from an older layout. Current readers merge older indexes where needed; sync.json is a migrated legacy record, not evidence that a current sync writer is running.Migration and compatibility readers.

See session I/O, session enrichment, stats, timeline, issue mirror, and claims.

Workspace projections and watcher infrastructure

These paths are relative to the state root.

PathContents and purpose
workspace/graph.jsonFiles/projects/groups and their graph attributes, paths, category/history information, and counts for Graph, Tree, and List. Served as /xo/space.json.
workspace/dashboard.jsonDashboard's category projection and project/file summary, derived from the graph scan. Served as /xo/dashboard.json.
workspace/sessions.jsonAggregate telemetry from available session providers: session/model/tool/token/cost/time breakdowns and source status. Served as /xo/sessions.json. It is separate from the watcher session index and does not contain prompt text.
workspace/sessions/sessionslist.jsonUnion of project session indexes.
workspace/sessions/sessions-augment.jsonUnion of project session enrichment.
workspace/stats.jsonSum of project runtime stats, including daily and rolling breakdowns.
workspace/timeline.jsonlCopies of rendered project timeline events with an added project_id. This is append-only history, not a fresh rescan of all old timelines.
watcher/offsets.jsonJSONL tail cursors: absolute source file path, byte offset, and inode. These paths can identify user directories.
watcher/hermes-offsets.jsonPer-profile/per-session SQLite message-row cursors for Hermes.
watcher/heartbeat.jsonLast successful tick time, tick counter, duration, and command-scheduler report.
watcher/activity/projects/<normalized-project>.jsonLive presence snapshot: runtime/session, model, user ID, known opening/activity times, and optional host. This location is keyed by normalized project name, not the project runtime pid.
watcher/activity/workspace.jsonUnion of project presence with project tags.
watcher/locks/<filename>.<hash>.lockLock sentinels for coordinated writes to data files. Their names identify a target file and a hash of its path; they are not activity records.

Presence is separate from history: a session can have historical usage and no current presence row. The current model cache is process-local, so a restarted watcher can need a new assistant usage event before it can publish a live row. Sources without process-presence support can contribute historical events while returning no live sessions. See the watcher, state paths, workspace writers, and lock implementation.

Inbox, connections, and sharing state

These paths are also relative to the state root. They include content and user choices, not just counters.

PathContents
inbox.jsonItems with titles, bodies, URLs, source/type, project links, timestamps, deduplication keys, new/seen/done status, feeder configuration/cursors, and automatic-close markers.
connections/accounts.jsonCached account label, connected-account ID, and last checked time per toolkit. It can exist even when no polling configuration exists.
connections/<toolkit>/config.jsonWhether polling is enabled, polling interval, and collector IDs.
connections/<toolkit>/state.jsonLast poll/success/error, seen event IDs per collector, and collected event count.
connections/<toolkit>/events.jsonl and rotated events.<timestamp>.jsonlSelected external-service content normalized to time/type/key/title/body/URL/toolkit. This can include email subjects/snippets, calendar descriptions, and message text.
project_sharing/<safe-repo-id>-<hash>.jsonPer-repository relay bookmarks: last reported commit SHA, consumed ledger cursor, and recorded clone time.

Sharing status also has an in-memory recent-event buffer. Inbox can retain a summary of a relay event after that buffer has changed. Deleting a connection's polling data does not retroactively delete its copied Inbox items. See the Inbox store, connection store, collectors, and sharing state.

Saved commands and schedules

Setup's Commands card uses the existing scheduler for both manual commands and interval jobs. Their files live under the machine-local state root, outside project .xo folders:

scheduler/
├── jobs.json          # command definitions and optional intervals
├── state.json         # next/last run, running marker, last result
├── runs/<id>.jsonl    # append-only results and raw output tails
└── logs/<id>.log      # appended full command output

A manual definition has no interval and never launches from a watcher tick. Run launches it explicitly; status reads collect completed results even when the watcher is off. Interval jobs share the same executor, concurrency limit, history, and logs. A server restart cannot resume a command: a remaining running marker is recorded as lost when reconciled.

Deleting a saved definition retains its history and logs and does not cancel an active process. Its eventual result can still be collected while the server remains running. Those files can outlive the command's row in Setup. The Quirq state view labels the directory and its files without returning their contents. The Commands card's separate API shows definitions and run output.

Configuration, credentials, logs, and scheduled work

The state root is not the only installation-owned directory. These exceptions matter when locating sensitive data or moving an installation.

LocationStored data
<state root>/state.jsonOnboarding completion and related local setup state.
<state root>/runtime.envAllowlisted non-secret runtime controls changed through Setup.
<state root>/roots.envPersisted projects/state-root choices for the next process start.
QUIRQ_SECRETS_FILEPlaintext provider/XO/channel credentials. The local installer sets this to <state root>/secrets.env; without that override, the active manifest's env_file is used. The writer uses owner-only permissions.
<xo-space checkout>/.envStartup environment when present. The backup configuration API also persists BACKUP_PASSWORD and optional GITHUB_PAT here. This remains separate from Setup's secrets-file path.
~/.config/token.jsonProvider-keyed OAuth/access/refresh credentials for direct connectors. Override: MCP_TOKENS_FILE. Written with owner-only permissions.
~/.config/composio/sessions.jsonComposio session ID, account/Space association, and local proxy tokens. Override the directory with COMPOSIO_STORE_DIR.
~/.config/composio/space_scope.jsonToolkit opt-in and connected-account pins for this Space.
~/.config/composio/action_prefs.jsonDisabled action slugs per toolkit. New actions default enabled within an enabled toolkit unless disabled here.
~/.config/rclone/rclone.confrclone's provider configuration and credentials when that connector is used.
${XDG_CONFIG_HOME:-~/.config}/quirq/install.jsonLast-known checkout, project and state-root paths, host, port, and boot timestamp for local discovery.
<state root>/quirq.logLocal installer's appended server stdout/stderr: startup, requests, warnings, failures, and feature diagnostics. Other launch methods can send these logs elsewhere.
<state root>/commands.log and commands.log.1Command label, arguments, working directory, status/duration, and bounded stdout/stderr. Recognized secret patterns are redacted; arbitrary command output is not guaranteed anonymous.
<state root>/scheduler/jobs.jsonManual and interval job definitions: name, description, command arguments, working directory, environment overrides, optional interval, timeout, enabled state, and optional project association.
<state root>/scheduler/state.jsonScheduling state, next/last run, running marker, and last result.
<state root>/scheduler/runs/<id>.jsonlAppend-only execution results: start/finish times, trigger, status, return code, duration, and a raw output tail up to 2,000 characters.
<state root>/scheduler/logs/<id>.logFull command execution output through the command logger.
<xo-space checkout>/data/<active-agent>/usage_sync_state.jsonDaily usage-reporting watermark and API-key probe bookkeeping. It does not contain the native transcript.

The command logger's redaction does not cover every persisted scheduler field: job definitions preserve supplied arguments/environment, and result records keep a raw output tail. Setup's write-only presentation also does not encrypt the underlying env file. Keep these stores within the appropriate local access boundary. See agent env, token store, Composio paths, backup config, command logger, scheduler, and usage reporting.

Native runtime stores and ingestion databases

Native runtimes own their conversations, tool inputs/results, authentication, and internal settings. Space's ability to read a subset is not a retention policy for the whole runtime home.

SourceNative locations and integration reads
Claude Code~/.claude/projects/<encoded-directory>/*.jsonl transcripts and ~/.claude/sessions/<pid>.json presence. The usage reader can use CLAUDE_PROJECTS_DIR. Native authentication/configuration also lives in Claude's own stores.
ArgusARGUS_DB, default ~/.argus/argus.db. The Claude aggregate Sessions provider queries this separate ingestion database. The Argus data directory also holds argusd.log and argusd.pid. xo-space starts the installed daemon through the adapter capability.
Codex$CODEX_HOME, default ~/.codex: sessions/YYYY/MM/DD/rollout-*.jsonl, history.jsonl, the latest versioned state_*.sqlite, config.toml, and auth.json where present. Aggregate telemetry uses the SQLite index plus rollout records.
Cursor$CURSOR_HOME, default ~/.cursor: projects/*/agent-transcripts and chats/**/store.db; desktop state.vscdb at platform-specific Cursor user-data paths. CURSOR_USER_DATA/CURSOR_DATA_DIR can direct discovery. Cursor contributes aggregate session telemetry, not a chat backend in this build.
OpenClawNative home, normally ~/.openclaw: agents/<agent>/sessions/<sid>.jsonl and each agent's sessions.json; openclaw.json, agent auth/model files, and runtime workspaces also belong to the native runtime.
HermesNative home, normally ~/.hermes: state.db and profiles/<profile>/state.db, plus profile configuration, env files, and gateway/provisioning logs.
AntigravityNormally ~/.gemini/antigravity-cli: brain/<conversation>/.system_generated/logs/transcript_full.jsonl, conversations/<id>.db, cache/last_conversations.json, settings.json, and antigravity-oauth-token.

SQLite readers and transcript adapters are described in the adapter source tree. Only Claude Code, Codex, and Cursor currently provide the aggregate Sessions capability. The watcher discovers a different capability, so these two lists need not match. See how collection works.

Argus stores more than the metric fields Space displays. In the pinned Argus 0.5.1 release, its database includes sessions, turns, tool-call metadata, source cursors, settings, alerts, and parse errors with short raw-line excerpts. It also ingests prompt display text from Claude's history.jsonl independently of the transcript-search toggle. Optional transcript indexing retains user, assistant, thinking, and tool-result segments plus full-text indexes. Disabling indexing does not remove those previously stored segments or prompt records. See the Argus collection boundary.

In-memory, browser, and temporary copies

“The transcript remains native” does not mean no content ever enters another buffer. File preview and prompt-detail requests necessarily read content into the server/browser. Their copies have a different lifetime from disk history.

LocationData and lifetime
Server processActive chat streams; source discovery/parsed-usage caches; latest model per session; sharing status; graph/history caches; and session prompt responses. Hermes also temporarily caches full user/assistant exchanges for up to 60 seconds while waiting for native database commits. Restarting loses this process-local state.
Session-prompt cacheUp to 32 (agent, session) results in server memory, with SPACE_CACHE_TTL defaulting to 30 seconds. The Sessions page also keeps fetched prompts in a page-lifetime map. Refreshing aggregate telemetry does not clear that browser map.
Browser previewCurrent/historical file text and preview history in memory. A one-shot sessionStorage record restores preview identity, selected version/source, and window geometry across an internal reload; it does not store the file body.
Browser preferenceslocalStorage retains the Atlas dataset choice and Timeline mode for that browser origin.
Temporary session MCP file/tmp/xo-cowork/<session>/mcp.json contains a localhost proxy URL with an opaque session token, not the upstream Composio credential. XO_MCP_TMP_ROOT overrides the root. The Claude adapter attempts cleanup after the run; startup sweeps orphaned directories.
Backup/restore temporary directoryTemporary repository checkout, plaintext compressed project archive, and encrypted chunks while an operation runs. The operation cleans its temporary directory when finished.

See prompt endpoint, Sessions UI, preview state, Atlas preferences, and temporary MCP config.

Copies created by backup and sharing

An encrypted project backup creates a private GitHub repository named xo-project-<project-id>. Each timestamped snapshot contains encrypted chunks and an unencrypted manifest.json: project/snapshot ID, time, byte size, hash, part names, git-origin URL, and optional note. The encryption protects the archive payload, not those manifest fields or the repository name.

For a git project, the archive includes tracked and untracked non-ignored files, plus .xo/ even if git ignores it. Mandatory exclusions still remove .env, .env.*, .git, node_modules, .venv, __pycache__, and socket files at any depth. A non-git project uses a filesystem walk with those exclusions. The state root and native homes are outside the archive when they are outside the project directory. If configured inside a project, the normal file-selection rules apply; there is no special exclusion for those roots. Arbitrarily named sensitive files inside a project are not detected by a content scan. See archive selection and snapshot manifest.

Git sharing has a different boundary: commits carry whatever the repository contains to its remote. The sharing relay records and exchanges repository identity and commit/ledger state; it does not turn a git push into an encrypted backup. A recipient's clone creates another copy of the shared repository. See Sharing and the relay implementation.

What happens to older layouts

Migration is specific to each store; it is not “move everything into .quirq.”

Older locationCurrent behavior
<project>/.xo/{stats,sync,activity}.json, timeline*.jsonl, and sessions/A one-time migration moves these into the project's runtime directory after an identity exists. Existing destination files win; compatible readers also have legacy read-through.
Runtime directory keyed by project name before pid was mintedAdopted into the stable pid directory. Existing destination files win when trees are merged.
Workspace .xo/dashboard.json, sessions.json, stats.json, activity.json, and sessions/Old derived views are removed and rebuilt under the state root.
Workspace .xo/timeline.jsonl and rotationsMoved to workspace/ rather than rebuilt. A same-named existing destination wins.
Old graph payload in workspace .xo/space.jsonReplaced by the current Space record; the graph has its own runtime view path.
Workspace .xo/inbox.jsonMoved to <state root>/inbox.json on first use if the destination is absent.
~/.xo-cowork/state.json and watcher cursorsLegacy read/migration sources for the current local-state and watcher stores. They are not the new write locations.
mcp-tokens.json in an older checkout/config locationMoved to the current token store on first access if it is absent.
Checkout data/composio_sessions.json, data/composio_action_prefs.json, or workspace_scope.jsonMigrated to the current Composio store filenames when the destination is absent. Session ownership stamps are checked before adoption.

Do not expect old and new copies to be merged into a complete audit history when both exist. Destination precedence is deliberate. The implementation details are in runtime migration, workspace migration, and each store linked above. Continue with collection and controls to understand which data is regenerated, retained, or sent to another service.