# How to Use the runtime.sqlite File in Apache Maka: A Complete Guide

> Learn how to use the runtime.sqlite file in Apache Maka. Access session events, tool-ledger entries, and workspace state programmatically for seamless operations.

- Repository: [The Apache Software Foundation/maka](https://github.com/apache/maka)
- Tags: how-to-guide
- Published: 2026-08-29

---

**The `runtime.sqlite` file is Maka's operational-state SQLite database that stores session events, tool-ledger entries, and workspace continuation state; access it programmatically using `acquireOperationalStateDatabase()` for safe concurrent connections or `createSqliteRuntimeStore()` for high-level CRUD operations.**

Apache Maka uses `runtime.sqlite` as the single source of truth for all runtime operational data. This SQLite database resides in your workspace storage root and manages everything from session events to tool-ledger integrity. Understanding how to interact with this file through Maka's TypeScript APIs enables you to build extensions, debug sessions, and perform migrations safely.

## What Is runtime.sqlite?

The `runtime.sqlite` file serves as the **operational-state database** within the Apache Maka ecosystem. According to the source code in [`packages/storage/src/operational-state-store.ts`](https://github.com/apache/maka/blob/main/packages/storage/src/operational-state-store.ts), this file maintains the authoritative record for session events, tool-ledger entries, workspace version authority, and continuation state. Unlike configuration files, this database is read and written during active Maka sessions, making proper access patterns critical for data integrity.

## Locating the Database File

By default, Maka places `runtime.sqlite` directly in the workspace root directory. The storage package provides a dedicated helper to resolve this path consistently across platforms.

```typescript
import { resolveOperationalStateDatabasePath } from '@maka/storage';

const dbPath = resolveOperationalStateDatabasePath(workspaceRoot);
// Returns: /path/to/workspace/runtime.sqlite

```

This function performs a standard `path.resolve(workspaceRoot, 'runtime.sqlite')` operation, ensuring cross-platform compatibility whether you are on Windows, macOS, or Linux.

## Core APIs for Database Access

Maka provides two primary entry points for interacting with `runtime.sqlite`, each designed for different concurrency and abstraction requirements.

### Low-Level Lease Management

For multi-component applications where several processes might access the database simultaneously, use `acquireOperationalStateDatabase()` defined in [`packages/storage/src/operational-state-store.ts`](https://github.com/apache/maka/blob/main/packages/storage/src/operational-state-store.ts). This function returns an `OperationalStateDatabaseLease` that implements reference counting and exclusive ownership guarantees.

```typescript
import { acquireOperationalStateDatabase } from '@maka/storage';

const lease = acquireOperationalStateDatabase(workspaceRoot);
// lease.database provides a node:sqlite DatabaseSync instance
// lease.transaction('write', () => { ... }) executes atomic transactions

```

The lease pattern prevents the "cannot rename an open SQLite database" error common on Windows and ensures the underlying connection closes automatically when the last holder calls `lease.close()`.

### High-Level Store Interface

For most application logic, `createSqliteRuntimeStore()` in [`packages/storage/src/sqlite-runtime-store.ts`](https://github.com/apache/maka/blob/main/packages/storage/src/sqlite-runtime-store.ts) offers a typed, promise-based API over the raw SQLite connection. This class exposes methods like `appendRuntimeEvent()`, `readImmutableRuntimeEvents()`, and `backup()` while handling schema migrations automatically.

```typescript
import { createSqliteRuntimeStore } from '@maka/storage';

const runtimeStore = createSqliteRuntimeStore(dbPath, { databaseLease: lease });
// or for read-only scripts:
const readStore = createSqliteRuntimeStore(dbPath, { readOnly: true });

```

When you supply a `databaseLease`, the store reuses the existing connection; otherwise, it manages its own file handle.

## Working with Runtime Events

The primary purpose of `runtime.sqlite` is persisting the canonical event stream that represents a Maka session's execution history.

### Appending Events

To record new tool calls or session milestones, use the `appendRuntimeEvent()` method. This automatically canonicalizes events and enforces tool-ledger invariants.

```typescript
import { encodeCanonicalRuntimeEvent } from '@maka/core/canonical-runtime-event';

const event = encodeCanonicalRuntimeEvent({
  id: 'event-1',
  sessionId: 'sess-123',
  runId: 'run-456',
  type: 'tool_call',
  toolName: 'search',
  args: { query: 'Maka architecture' },
});

await runtimeStore.appendRuntimeEvent('sess-123', 'run-456', event);

```

### Reading Event History

Retrieve immutable event logs for debugging or audit purposes using `readImmutableRuntimeEvents()`. This returns the complete ordered history for a specific session and run combination.

```typescript
const events = await runtimeStore.readImmutableRuntimeEvents('sess-123', 'run-456');
// Returns array of canonical runtime events

```

## Database Maintenance and Migration

Maka automatically manages schema evolution between versions, but you can inspect and maintain the database manually when necessary.

### Schema Versioning and Migrations

The constructor of `SqliteRuntimeStore` automatically invokes `configureSqliteRuntimeDatabase()` and `migrateSqliteRuntimeDatabase()` from [`packages/storage/src/sqlite-runtime-schema.ts`](https://github.com/apache/maka/blob/main/packages/storage/src/sqlite-runtime-schema.ts). You can verify the current schema state using:

```typescript
const version = runtimeStore.schemaVersion();     // e.g., 2
const journalMode = runtimeStore.journalMode();   // typically 'wal'

```

If the version is lower than `SQLITE_RUNTIME_SCHEMA_VERSION` (defined in the schema module), the migration routines execute automatically to bring older `runtime.sqlite` files up to date.

### Creating Backups

Before major migrations or for disaster recovery, use the lease's `backup()` method, which wraps SQLite's native backup API for fast, consistent copies.

```typescript
const bytesCopied = await lease.backup('/path/to/backup/runtime.sqlite');
console.log(`Backed up ${bytesCopied} bytes`);

```

This method validates that the destination path differs from the source and performs a page-by-page copy without locking the database for extended periods.

## Direct Access vs. Lease-Based Access

Choose your access pattern based on concurrency requirements and operational context:

- **Lease-based access**: Required when multiple components (session manager, tool ledger, workspace-version authority) share the database. Prevents file-handle leaks and Windows file-locking issues through automatic reference counting.
- **Direct store access**: Suitable for single-process scripts or read-only analysis tools where you open the file, query data, and exit immediately.

For read-only inspection without the overhead of lease management:

```typescript
const store = createSqliteRuntimeStore('/path/to/runtime.sqlite', { readOnly: true });
const events = await store.readImmutableRuntimeEvents('sess-1', 'run-1');

```

## Complete Code Examples

### Listing All Runs for a Session

For audit scripts or debugging tools, query the database directly using the store's underlying connection:

```typescript
import { resolveOperationalStateDatabasePath, createSqliteRuntimeStore } from '@maka/storage';

async function listRuns(workspaceRoot: string) {
  const dbPath = resolveOperationalStateDatabasePath(workspaceRoot);
  const store = createSqliteRuntimeStore(dbPath, { readOnly: true });

  const runs = store.db.prepare(`
    SELECT DISTINCT run_id FROM runtime_events
    WHERE session_id = ?
  `).all('my-session') as { run_id: string }[];

  console.log('Runs for session "my-session":', runs.map(r => r.run_id));
}

```

### Recording Tool Calls with Lease Management

When integrating with the active Maka runtime, always acquire a lease to ensure safe concurrent access:

```typescript
import {
  acquireOperationalStateDatabase,
  createSqliteRuntimeStore,
} from '@maka/storage';
import { encodeCanonicalRuntimeEvent } from '@maka/core/canonical-runtime-event';

async function recordToolCall(root: string, sessionId: string, runId: string) {
  const lease = acquireOperationalStateDatabase(root);
  const store = createSqliteRuntimeStore(root, { databaseLease: lease });

  const event = encodeCanonicalRuntimeEvent({
    id: 'event-1',
    sessionId,
    runId,
    type: 'tool_call',
    toolName: 'search',
    args: { query: 'Maka architecture' },
  });

  await store.appendRuntimeEvent(sessionId, runId, event);
  lease.close(); // Releases reference count and closes connection if last holder
}

```

### Automated Backup Routine

Implement disaster recovery by backing up the database before critical operations:

```typescript
import {
  acquireOperationalStateDatabase,
  resolveOperationalStateDatabasePath,
} from '@maka/storage';
import { join } from 'node:path';

async function backupRuntime(root: string) {
  const lease = acquireOperationalStateDatabase(root);
  const backupPath = join('/tmp/backups', 'runtime.sqlite');
  
  await lease.backup(backupPath);
  console.log('Backup saved to', backupPath);
  
  lease.close();
}

```

## Summary

- The `runtime.sqlite` file in Apache Maka stores all operational state including session events and tool-ledger entries at the workspace root.
- Use `resolveOperationalStateDatabasePath()` to locate the file, `acquireOperationalStateDatabase()` to obtain a concurrency-safe lease, and `createSqliteRuntimeStore()` for high-level data operations.
- The lease pattern prevents file-locking issues on Windows and ensures automatic cleanup of database connections through reference counting.
- `SqliteRuntimeStore` automatically handles schema migrations defined in [`packages/storage/src/sqlite-runtime-schema.ts`](https://github.com/apache/maka/blob/main/packages/storage/src/sqlite-runtime-schema.ts), bringing older databases up to the current `SQLITE_RUNTIME_SCHEMA_VERSION`.
- For read-only analysis scripts, you can bypass the lease and open the database directly with the `readOnly: true` option.

## Frequently Asked Questions

### Where is the runtime.sqlite file located in a Maka workspace?

By default, Maka creates `runtime.sqlite` in the root directory of your workspace. The `@maka/storage` package exports `resolveOperationalStateDatabasePath(workspaceRoot)` to reliably resolve this location across operating systems, performing a platform-aware path join between the workspace root and the filename `'runtime.sqlite'`.

### How do I prevent database locking errors when accessing runtime.sqlite?

Always use `acquireOperationalStateDatabase()` to obtain an `OperationalStateDatabaseLease` before writing to the database. This lease implements reference counting and guarantees that only one process-local owner holds the connection at a time, which prevents the "database is locked" and "cannot rename an open SQLite database" errors common on Windows and busy systems.

### Can I read from runtime.sqlite without acquiring a lease?

Yes, for simple read-only scenarios or offline analysis, you can call `createSqliteRuntimeStore(dbPath, { readOnly: true })` without providing a `databaseLease`. This opens an independent connection to the SQLite file suitable for querying events or inspecting schema versions, though you should avoid this pattern in active Maka extensions that run concurrently with the main process.

### How does Maka handle schema migrations for runtime.sqlite?

Maka automatically manages migrations through the `SqliteRuntimeStore` constructor, which invokes `configureSqliteRuntimeDatabase()` and `migrateSqliteRuntimeDatabase()` from [`packages/storage/src/sqlite-runtime-schema.ts`](https://github.com/apache/maka/blob/main/packages/storage/src/sqlite-runtime-schema.ts). These functions check the current `schemaVersion()` against `SQLITE_RUNTIME_SCHEMA_VERSION` and apply incremental migrations to bring the database up to date without manual intervention.