FabricFabricHarness
EcosystemDatabases

MySQL

Add least-privilege, parameterized MySQL tools.

Runtime persistence

pnpm add @fabric-harness/node mysql2
.fabricharness/config.ts
import { mysqlPersistence } from '@fabric-harness/node';
import mysql from 'mysql2/promise';

export default function config() {
  const pool = mysql.createPool(process.env.MYSQL_URL!);
  return { persistence: mysqlPersistence({ client: pool }) };
}

mysqlPersistence() supplies sessions, submissions, conversation streams, binary attachments, runs/events, atomic cost budgets, health, migration, and cascade deletion. It stores one version-fenced JSON snapshot per persistence surface and uses compare-and-swap updates, so multiple replicas cannot both commit the same transition.

Use MySQL 8/InnoDB, TLS, backups, and a max_allowed_packet larger than your largest attachment snapshot. Snapshot rows favor moderate agent operational state; use Postgres when workloads have very high write concurrency or histories large enough that rewriting a surface snapshot is costly.

Governed data tools

Use the fixed-statement MySQL tool. Scaffold mysql2 and @fabric-harness/databases/mysql with:

fh add database mysql
const lookup = mysqlTool({
  client: pool,
  name: 'lookup_account',
  description: 'Read one tenant-scoped account.',
  statement: 'select id, status from accounts where tenant_id = ? and id = ? limit 1',
  parameters: ({ tenantId, accountId }) => [tenantId, accountId],
});

The application owns the SQL; model input only becomes bound parameters. Read tools reject mutations and multi-statements. Use a least-privilege user, keep multipleStatements: false, and mark controlled mutations effect: 'write' so approvals can gate them.

Runtime credentials stay in host configuration and are never added to model-facing tools.