All documentation

Local storage

What OpenOrc stores on your computer, in which files and tables, how long it keeps it, and what deleting removes.

Checked against the source on September 27, 2026.

The profile folder

OpenOrc keeps its own data in one folder: ~/Library/Application Support/OpenOrc on macOS, %APPDATA%\OpenOrc on Windows, or the folder named by OPENORC_USER_DATA. Electron keeps its own browser data in the same folder. Git data OpenOrc creates, such as worktree branches and refs under refs/openorc/, lives in your repositories (see Git and review), and two actions write files into your project: exporting a plan, and adding a memory to CLAUDE.md or AGENTS.md.

OpenOrc also makes short-lived private folders in your system's temporary folder: one per Claude Code process for the file that holds OpenOrc's MCP address, scratch space for background text jobs such as memory extraction, and scratch copies for Git operations. Each is deleted when its job ends. When a Claude Code conversation runs in Plan mode, OpenOrc creates Claude's plans folder, ~/.claude/plans (or plans inside CLAUDE_CONFIG_DIR), if it does not exist.

PathContents
openorc.sqlite, -wal, -shmThe database and its write-ahead log. Back up all three together.
attachments/Files you attached: images under a random name, other files under a random ID followed by their original name
tool-images/<run>/Images that tools returned as base64
worktrees/<project>/…Worktrees for conversations and tasks that use them
workspace/The default folder for Workspace conversations
logs/provider/Native agent output, kept up to 14 days or 512 MB
models/The embedding model used by project memory, downloaded the first time memory needs it
updates.json, .updaterIdWhether installed releases check for updates on their own, and a random ID the update library keeps for gradual rollouts. OpenOrc does not send the ID.
slack-secrets.enc, memory-extraction-key.encEncrypted Slack configuration and the optional memory API key
exports/Patch files you exported from a task
task-checkout/, task-forwardings/Scratch copies used when applying a task to your checkout or moving a task
team-workspaces/, team-integrations/, team-forks/, team-restores/, team-moves/, team-avatars/Folders used by the team preview

Worktrees include copies of your project's .env and .env.* files by default, so agents can run the project. The list of copied files is a project setting. Treat the whole profile folder as private: it holds your prompts, source snippets, command output, and those copies.

The database

OpenOrc uses SQLite through Node's built-in node:sqlite module. The core opens one connection at startup and keeps it; the main process and the interface never open the database. The connection is synchronous: one writer, and no locks held across await.

PRAGMA auto_vacuum = INCREMENTAL;
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
PRAGMA busy_timeout = 5000;
PRAGMA foreign_keys = ON;

With write-ahead logging and synchronous = NORMAL, committed writes survive an app crash, but the last moments before an OS crash or power loss can be lost.

Transactions

Every transaction is a named savepoint, so a function that opens a transaction can call another that does too. Only the outermost savepoint commits. An error rolls back to the savepoint and is rethrown.

Migrations

The schema is an ordered list of migrations in packages/db/src/schema.ts, and PRAGMA user_version records how many have run. Each pending migration runs in its own transaction with foreign keys switched off, must pass PRAGMA foreign_key_check, then bumps user_version. A failed migration rolls back and stops startup. Migrations that have shipped are never edited; changes are always new migrations. Tests build older databases by running a prefix of the list and then open them with the current code.

Source: packages/db/src/database.ts, schema.ts

Tables

The tables by area are below. Most of the schema's triggers protect the team preview's records.

AreaTables
Workprojects, threads, tasks, runs, thread_messages, thread_queue, conversation_plans, conversation_plan_turns
Eventsevents, artifacts, audit_events
Changes and reviewthread_checkpoints, snapshots, review_comments
Task discussionstask_comments, task_comment_attempts
Schedulesschedules, schedule_firings
Memorymemories, memory_files, session_summaries, extraction_jobs
Settingssettings
Searchmessages_fts and memories_fts (SQLite FTS5), memory_vec (sqlite-vec)
Team previewTeam definitions and revisions (orchestration_*), executions and their journals (team_executions, team_actors, team_attempts, team_attempt_prompts, team_messages, team_claims), bindings between runs, assignments, and team members, workspaces and their publication, room messages and deliveries, task admissions and completions, and receipts for forks, restores, moves, and deletions

audit_events records about 50 kinds of action with who took them (you, an agent, or OpenOrc itself): starting runs, creating tasks, committing, pushing, restoring files, approvals OpenOrc decided without asking, and so on.

The event ledger

The events table holds every event agents produced, one row each: the run, a sequence number within the run, the time, the event type, the tool name if any, and the event as JSON. raw events are not stored here; they go to the provider log.

  • Batching. Events are queued in memory and written in one transaction every 50 ms, or as soon as 500 are waiting. Reads flush the queue first. An event still in the queue when the process crashes is lost.
  • Large payloads. An event over 8 KiB is stored in artifacts, and the event row keeps a 1 KiB preview. Both are in the same database file.
  • Images. Base64 images in tool results are written to tool-images/ first, and the event stores an openorc-asset: link.
  • Streaming fragments. A streamed message arrives as many small deltas followed by a completed event. Once the completed event is written, the deltas in between are deleted in the same transaction. The first delta is kept, because the transcript places the item at its first row. Thinking, tool output, and activity updates follow the same rule when their final event carries the full content.

The interface reads the ledger a few turns at a time with events.page, using an index on turn boundaries. Tool results whose stored event is over 4,096 characters are returned without their output until you open them.

Source: packages/db/src/ledger.ts, fragments.ts, transcript-page.ts

Conversation search uses messages_fts, an FTS5 table that stores the redacted text of every user and assistant message. Tool output and reasoning are not indexed. A query keeps up to 8 words, and every word must match as a prefix. Results are ranked with BM25, newest first on ties; the command palette shows up to 20.

Memory search uses its own index; see Project memory.

Source: packages/db/src/search.ts

Redaction

Before OpenOrc writes an agent event, it redacts each string inside the event on its own. A secret that starts a new line is found, and a match never runs from one string into the next. The same filter runs before OpenOrc stores:

  • ledger events, including large payloads and the previews kept in their place, and the search index built from them;
  • run results and errors, the audit log, the provider log, and the conversation message log;
  • memories, run summaries, and extraction errors;
  • Slack requests waiting for your computer.

A match is replaced with a marker such as [redacted:github-token]. The filter looks for:

  • Known token shapes: GitHub (ghp_, github_pat_), GitLab (glpat-), Slack (xoxb- and similar, xapp-), Anthropic (sk-ant-), OpenAI (sk-), Stripe, npm (npm_), and Hugging Face (hf_) tokens, Google API keys, AWS access key IDs, OpenOrc device keys, JSON Web Tokens, and private keys, including one cut off before its end line.
  • Credentials in context: the token after Bearer or Basic, the password in a URL such as postgres://user:password@host, and a value of 8 or more characters assigned to a secret name, as in DB_PASSWORD=…, "api_key": "…", or X-Api-Key: ….
  • Secret fields: in structured data, such as a tool's input, the whole value of a field with a secret name, or one named cookie.

A secret name ends in api key, secret, client secret, access token, auth token, refresh token, private key, password, passwd, or authorization, in any case and with any prefix, such as PGPASSWORD. Code that only refers to a secret is left alone, such as apiKey: process.env.API_KEY, password: form.password, or a function call.

This filter catches common formats. It is not a guarantee: it misses a secret with no known shape or name, such as a password written in a sentence, and it sometimes hides ordinary text that looks like one. Some text is stored as written:

  • Text an agent receives later: plans, task comments, review comments, team messages, and messages you queue in a conversation, which stay stored after they are sent. Redacting them would change what the agent gets.
  • Text you write and edit: drafts, task specs, and schedule prompts.
  • Everything outside OpenOrc's records: your project and its Git history, .env copies in worktrees, and the transcripts the agent CLIs keep for themselves, such as ~/.claude/projects and ~/.codex/sessions.

Redaction changes only what OpenOrc stores. The agent receives your messages and its tool output as they are. The filter runs when text is written, so improving it later does not rewrite what is already stored.

Source: packages/db/src/redact.ts, ledger.ts, repos.ts, memories.ts

Upkeep and retention

At startup, if the database file predates incremental vacuuming and at least 64 MiB and a quarter of it are free space, OpenOrc rebuilds it once with VACUUM on a separate connection in a worker thread. It skips this when disk space is low, or when it failed in the last 3 days.

A background pass runs 60 seconds after startup and then every 6 hours:

  1. Deletes raw event rows older than 14 days, in batches of 500. Newer versions no longer write these rows.
  2. Once, removes redundant streaming fragments that older versions stored.
  3. Returns free pages to the file system with PRAGMA incremental_vacuum.
  4. Removes search rows and tool image folders that belong to deleted runs.

Nothing else expires. Conversations, events, runs, and memories stay until you delete them, and OpenOrc never removes attachments or audit log entries. There is no size limit on the database.

Source: packages/core/src/services/ledger-upkeep.ts, packages/db/src/maintenance.ts

Settings and secrets

App settings are one JSON row in the settings table, validated with zod when read. The same key-value table holds memory settings, text generation settings, receipts that stop an action from running twice (such as implementing a plan revision), and Slack bookkeeping. Project settings are stored as JSON on each project row.

Secrets are not stored in the database. Slack tokens and the optional memory API key are encrypted by the main process with Electron's safeStorage, which uses the macOS Keychain, Windows DPAPI, or the Linux secret service. OpenOrc refuses to save them on Linux systems where safeStorage falls back to plain text.

  • Writes go to a temporary file with owner-only permissions, are synced to disk, and then replace the old file.
  • The interface can submit secrets but can never read them back; it only sees whether one is saved. The one exception is a new Slack device key, which is shown once when you add a device so you can pass it on. The relay host keeps only a hash of it.
  • Older versions stored the memory API key in the settings table. On first read, it is moved to the encrypted file, deleted with SQLite's secure_delete, and the database is rebuilt so no copy remains in free pages.

On macOS and Linux, development and packaged builds use different keychain entries, so a key saved by one cannot be decrypted by the other.

Source: packages/core/src/services/settings.ts, extraction-credentials.ts, apps/desktop/src/main/protected-secrets.ts

Window storage

The interface also keeps a little data in Chromium's storage inside the profile folder:

  • Local storage: composer drafts (openorc.draft.*), layout, and theme.
  • IndexedDB: images pasted into task documents (openorc-image-drafts).
  • The Preview browser's own session, with the cookies and site data of pages you open there.

What deleting removes

Deleting a conversation

OpenOrc closes its agent process and removes its worktree, if it has one and no fork of the conversation still uses it. Uncommitted changes there are committed to the worktree's branch first, and the branch stays. The refs that pinned its checkpoints are deleted. In the database, the delete cascades to its runs and their events, artifacts, run summaries, plans, snapshots of its files, review comments, queued messages, and Slack messages. Search rows and tool images for those runs are removed right after.

These stay:

  • Tasks that belonged to the conversation, now unlinked.
  • Attachments you sent in it.
  • Memories extracted from it.
  • Audit log entries.
  • Its lines in the provider log, until they expire.
  • The providers' own session files, such as ~/.claude/projects/… and ~/.codex/sessions/…, which OpenOrc never deletes.
  • Anything the provider keeps on its servers under its own terms.

Deleting a task

Delete task appears only on team tasks, in the task's Task panel. Ordinary tasks cannot be deleted from the app. Deleting a task removes it, its discussion with the runs of the replies, and any runs that belonged to the task itself. Work done on the task in its conversation stays in that conversation, and so do review comments left on that conversation's changes; they only lose their link to the task. Review comments that belong to the task alone, which come from team review, are deleted with it.

Projects

Projects cannot be deleted yet.

SQLite reuses the space of deleted rows but does not overwrite it, so deleted text can remain in the file until those pages are reused or compacted.

Source: packages/core/src/services/threads.ts (delete), packages/core/src/openorc.ts, packages/db/src/schema.ts, repos.ts