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 guide | How it resolves |
|---|---|
| Projects root | XO_PROJECTS_ROOT. The local installer uses the directory where you run it; the service's standalone fallback is ~/xo-projects. |
| State root | QUIRQ_STATE_ROOT. The local installer uses <workspace>/.quirq; the service's standalone fallback is ~/.quirq. |
| Project | A project directory inside the projects root. Its .xo/project.json carries its stable identity. |
| Project runtime key | Normally 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 home | The 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.
<projects root>/.xo/space.jsonWorkspace identity.<projects root>/<project>/.xo/Project identity, todos, workitems and peer records.
<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.
Agent homes · native databases and logsOriginal conversations and runtime records. Space reads supported data and can retain selected details in its own indexes.Argus storeSeparate Claude Code ingestion database used for aggregate usage.
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 project | Data and writer |
|---|---|
AGENTS.md, PROJECT.md, OBJECTIVES.md, PLAN.md, PROGRESS.md, memory/, and ordinary output files | Human- 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.json | Stable 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.json | Optional 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.json | Authored session steps, runtime/session association, content, description, active form, status, timestamps, and deletion tombstones. The Todo API is the writer. |
.xo/workitems.json | Authored 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.json | The 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/ directories | Reserved 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
| Path | Data and writer |
|---|---|
<projects root>/.xo/space.json | The Space record: identity, owner, label, configured roots, attached backend capabilities, availability, and first/last-use timestamps. |
<projects root>/.xo/projects.json | Directory registry: project names, stable IDs, scaffold state, and git origin. Refreshed from the actual project directories. |
<projects root>/.xo/xo.json | Frontend 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.
| Path | Contents | Producing feature |
|---|---|---|
sessions/sessionslist.d/<hash>.json | One 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.json | Per-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.json | Rolling 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>.jsonl | Normalized 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.json | GitHub 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.json | Which 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.json | Compatibility 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.
| Path | Contents and purpose |
|---|---|
workspace/graph.json | Files/projects/groups and their graph attributes, paths, category/history information, and counts for Graph, Tree, and List. Served as /xo/space.json. |
workspace/dashboard.json | Dashboard's category projection and project/file summary, derived from the graph scan. Served as /xo/dashboard.json. |
workspace/sessions.json | Aggregate 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.json | Union of project session indexes. |
workspace/sessions/sessions-augment.json | Union of project session enrichment. |
workspace/stats.json | Sum of project runtime stats, including daily and rolling breakdowns. |
workspace/timeline.jsonl | Copies 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.json | JSONL tail cursors: absolute source file path, byte offset, and inode. These paths can identify user directories. |
watcher/hermes-offsets.json | Per-profile/per-session SQLite message-row cursors for Hermes. |
watcher/heartbeat.json | Last successful tick time, tick counter, duration, and command-scheduler report. |
watcher/activity/projects/<normalized-project>.json | Live 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.json | Union of project presence with project tags. |
watcher/locks/<filename>.<hash>.lock | Lock 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.
| Path | Contents |
|---|---|
inbox.json | Items with titles, bodies, URLs, source/type, project links, timestamps, deduplication keys, new/seen/done status, feeder configuration/cursors, and automatic-close markers. |
connections/accounts.json | Cached account label, connected-account ID, and last checked time per toolkit. It can exist even when no polling configuration exists. |
connections/<toolkit>/config.json | Whether polling is enabled, polling interval, and collector IDs. |
connections/<toolkit>/state.json | Last poll/success/error, seen event IDs per collector, and collected event count. |
connections/<toolkit>/events.jsonl and rotated events.<timestamp>.jsonl | Selected 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>.json | Per-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 outputA 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.
| Location | Stored data |
|---|---|
<state root>/state.json | Onboarding completion and related local setup state. |
<state root>/runtime.env | Allowlisted non-secret runtime controls changed through Setup. |
<state root>/roots.env | Persisted projects/state-root choices for the next process start. |
QUIRQ_SECRETS_FILE | Plaintext 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>/.env | Startup 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.json | Provider-keyed OAuth/access/refresh credentials for direct connectors. Override: MCP_TOKENS_FILE. Written with owner-only permissions. |
~/.config/composio/sessions.json | Composio session ID, account/Space association, and local proxy tokens. Override the directory with COMPOSIO_STORE_DIR. |
~/.config/composio/space_scope.json | Toolkit opt-in and connected-account pins for this Space. |
~/.config/composio/action_prefs.json | Disabled action slugs per toolkit. New actions default enabled within an enabled toolkit unless disabled here. |
~/.config/rclone/rclone.conf | rclone's provider configuration and credentials when that connector is used. |
${XDG_CONFIG_HOME:-~/.config}/quirq/install.json | Last-known checkout, project and state-root paths, host, port, and boot timestamp for local discovery. |
<state root>/quirq.log | Local 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.1 | Command 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.json | Manual 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.json | Scheduling state, next/last run, running marker, and last result. |
<state root>/scheduler/runs/<id>.jsonl | Append-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>.log | Full command execution output through the command logger. |
<xo-space checkout>/data/<active-agent>/usage_sync_state.json | Daily 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.
| Source | Native 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. |
| Argus | ARGUS_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. |
| OpenClaw | Native 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. |
| Hermes | Native home, normally ~/.hermes: state.db and profiles/<profile>/state.db, plus profile configuration, env files, and gateway/provisioning logs. |
| Antigravity | Normally ~/.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.
| Location | Data and lifetime |
|---|---|
| Server process | Active 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 cache | Up 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 preview | Current/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 preferences | localStorage 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 directory | Temporary 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 location | Current 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 minted | Adopted 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 rotations | Moved to workspace/ rather than rebuilt. A same-named existing destination wins. |
Old graph payload in workspace .xo/space.json | Replaced by the current Space record; the graph has its own runtime view path. |
Workspace .xo/inbox.json | Moved to <state root>/inbox.json on first use if the destination is absent. |
~/.xo-cowork/state.json and watcher cursors | Legacy 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 location | Moved 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.json | Migrated 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.