DEV Community

jaryn
jaryn

Posted on

Use SQLite STRICT Tables for Agent Control Data

An AI coding workflow may generate probabilistic output, but its authority should not be probabilistic. Task state, approval scope, repository identity, and policy version are control data. If one of those values is malformed, silently coercing it is a dangerous default.

This is why the current discussion around SQLite strict tables is relevant to agent systems. At 2026-07-12 08:00 UTC, Evan Hahn's article “Prefer strict tables in SQLite” was the highest-scoring item in the Hacker News snapshot I reviewed, with 267 points. SQLite's own STRICT tables documentation is the source of truth for the feature.

The useful lesson is narrower than “make everything strict”: put strong boundaries around the small set of records that decide what an automated tool may do.

A control-data schema

CREATE TABLE agent_task (
  task_id TEXT PRIMARY KEY,
  repo_id TEXT NOT NULL,
  requested_by TEXT NOT NULL,
  state TEXT NOT NULL CHECK (
    state IN ('queued', 'running', 'awaiting_approval', 'succeeded', 'failed', 'cancelled')
  ),
  policy_version TEXT NOT NULL,
  approved_commit TEXT,
  approval_expires_at INTEGER,
  created_at INTEGER NOT NULL,
  updated_at INTEGER NOT NULL
) STRICT;

CREATE TABLE tool_grant (
  task_id TEXT NOT NULL REFERENCES agent_task(task_id),
  tool TEXT NOT NULL,
  resource_pattern TEXT NOT NULL,
  effect TEXT NOT NULL CHECK (effect IN ('allow', 'deny')),
  granted_by TEXT NOT NULL,
  expires_at INTEGER NOT NULL,
  PRIMARY KEY (task_id, tool, resource_pattern)
) STRICT;
Enter fullscreen mode Exit fullscreen mode

STRICT does not create a complete authorization system. It does make invalid storage less ambiguous: values must be compatible with the declared types, and SQLite reports a constraint error rather than accepting arbitrary type substitutions. CHECK constraints still carry the domain rules.

Validate the decision, not only the row

Before a worker changes a repository, the application should evaluate all of these inputs together:

Question Reject when
Is this the intended repository? repo_id does not match the checked-out remote
Is the approval current? expiry is in the past or absent for a privileged tool
Is the code revision pinned? approved_commit differs from the worker's base commit
Is the policy reproducible? policy_version cannot be loaded
Is the transition legal? current and requested states are not an allowed edge

A defensive transition can be one conditional statement:

UPDATE agent_task
SET state = 'running', updated_at = unixepoch()
WHERE task_id = :task_id
  AND state = 'queued'
  AND policy_version = :loaded_policy;
Enter fullscreen mode Exit fullscreen mode

The worker proceeds only when exactly one row changed. That turns a race or stale assumption into a visible failure.

Threat model and limits

This boundary helps with accidental type coercion, illegal states, stale approvals, and concurrent transitions. It does not stop a process that can rewrite the database file, bypass the application, steal signing credentials, or alter the policy loader. File permissions, process isolation, append-only audit export, backups, and independent review remain separate controls.

Run PRAGMA integrity_check; as part of recovery testing, but do not confuse integrity with authorization. A structurally valid database can still contain a maliciously granted permission.

Where MonkeyCode fits

The public MonkeyCode repository describes an open-source AI coding platform with AI task, development-environment, model, and project-requirement management, plus private deployment. That makes control-data boundaries relevant when evaluating a deployment. The schema above is an independent review pattern; it is not a claim about MonkeyCode's internal database design.

Disclosure: I contribute to the MonkeyCode project. The observations and limitations below are based on the linked repository and the test setup described in this article.

If you are evaluating the platform, ask the team in the MonkeyCode Discord how task state, approvals, and policy versions are represented in the version you plan to run. You can also ask whether free model credits are currently available and confirm eligibility and usage limits.

The practical rule is simple: model output can remain flexible; the records that grant authority should fail closed.

Top comments (0)