Operation Plans

Every write to Lore goes through a JSON plan. The plan describes what to change, and Lore executes it atomically.

Plan Format

{
  "baseSchemaHash": "a1b2c3...64 hex chars",
  "message": "Add expenses table and first entry",
  "operations": [...]
}
FieldDescription
baseSchemaHashSHA-256 of the current schema, obtained from lore schema output
messageCommit message describing the change
operationsArray of operations to execute in order

Schema Operations

create_table

Create a new table. Exactly one column must have primaryKey: true.

{
  "type": "create_table",
  "table": "expenses",
  "columns": [
    { "name": "id", "type": "INTEGER", "primaryKey": true },
    { "name": "title", "type": "TEXT", "notNull": true },
    { "name": "amount", "type": "REAL" },
    { "name": "date", "type": "TEXT" },
    { "name": "created_at", "type": "TEXT",
      "default": { "kind": "sql", "expr": "CURRENT_TIMESTAMP" } }
  ]
}

Column defaults support two kinds:

  • { "kind": "literal", "value": 0 } — a static value
  • { "kind": "sql", "expr": "CURRENT_TIMESTAMP" } — a SQL expression (CURRENT_TIMESTAMP, CURRENT_DATE, or CURRENT_TIME)

add_column

Add a column to an existing table.

{
  "type": "add_column",
  "table": "expenses",
  "column": { "name": "location", "type": "TEXT" }
}

If notNull is true, a default is required. SQL expression defaults are only allowed on empty tables. primaryKey and unique columns cannot be added this way.

alter_column_type

Change a column’s type.

{
  "type": "alter_column_type",
  "table": "expenses",
  "column": "amount",
  "newType": "REAL"
}

drop_table

{ "type": "drop_table", "table": "expenses" }

drop_column

{ "type": "drop_column", "table": "expenses", "column": "location" }

add_check

Add a CHECK constraint to a table.

{
  "type": "add_check",
  "table": "tasks",
  "expression": "status IN ('todo','doing','done')"
}

drop_check

{
  "type": "drop_check",
  "table": "tasks",
  "expression": "status IN ('todo','doing','done')"
}

drop_index

{ "type": "drop_index", "table": "expenses", "name": "idx_expenses_date" }

drop_trigger

{ "type": "drop_trigger", "table": "expenses", "name": "trig_after_insert" }

drop_view

{ "type": "drop_view", "name": "monthly_summary" }

Data Operations

insert

{
  "type": "insert",
  "table": "expenses",
  "values": {
    "title": "Coffee with Sarah",
    "amount": 4.50,
    "date": "2026-02-27"
  }
}

update

{
  "type": "update",
  "table": "expenses",
  "values": { "amount": 5.00 },
  "where": { "id": 1 }
}

where is required and must be non-empty.

delete

{
  "type": "delete",
  "table": "expenses",
  "where": { "id": 1 }
}

where is required and must be non-empty.

Value Types

Values in insert, update, and where clauses support: string, number, boolean, and null.

Naming Rules

Table and column names must contain only letters, digits, and underscores. Names starting with _lore_ or sqlite_ are reserved.

Dependency Conflicts

When dropping a table or column, Lore checks for dependent objects — indexes, triggers, views, foreign keys, and generated columns. If conflicts exist, the operation fails with DEPENDENCY_CONFLICT and a suggestedOps array listing the drop operations needed first.

For example, dropping a column that has an index will suggest a drop_index operation that should be added before the drop_column.