manage-database-usage
Manage Database Usage (Doltgres)
The manage database is a Doltgres instance (PostgreSQL with Git-like versioning). Every read or write must happen on the correct branch. Failing to scope connections to a branch will read/write the wrong data.
Branch Naming
Each project has its own main branch: <tenantId>_<projectId>_main.
Custom branches follow: <tenantId>_<projectId>_<branchName>.
Connections default to the main branch (which is empty/root), so you must always check out the correct project branch before any operation.
Decision Table
| Where is your code? | What to use |
|---|---|
/manage route handler |
c.get('db') — middleware handles checkout and commit |
/run or /evals route handler |
withRef(manageDbPool, resolvedRef, (db) => ...) |
| Service class or utility outside manage routes | withRef(manageDbPool, resolvedRef, (db) => ...) |
Already inside a withRef callback |
Use the db from the callback argument directly |
Mechanism 1: Middleware (/manage routes)
The branchScopedDbMiddleware (in agents-api/src/middleware/branchScopedDb.ts) runs on all /manage routes. It:
- Acquires a dedicated connection from the pool
- Checks out the correct branch (from the request's resolved
ref) - Creates a Drizzle client scoped to that connection
- Injects it into context as
'db' - Executes the route handler
- Auto-commits on success for write operations
- Cleans up: checks out
mainand releases connection
Usage
async (c) => {
const db: AgentsManageDatabaseClient = c.get('db');
const { tenantId, projectId } = c.req.valid('param');
const tools = await listTools(db)({
scopes: { tenantId, projectId },
});
return c.json({ data: tools });
}
Rules
- ALWAYS use
c.get('db')inside manage routes — never import and use the globalmanageDbClientdirectly (it isn't checked out to any branch) - Don't manually commit — the middleware auto-commits successful writes and resets on failure
- The
resolvedRefis also available viac.get('resolvedRef')if needed
Mechanism 2: withRef (outside manage routes)
Use withRef from @inkeep/agents-core (defined in packages/agents-core/src/dolt/ref-scope.ts) when accessing manage data from /run, /evals, services, or other packages.
Read
import { withRef } from '@inkeep/agents-core';
import manageDbPool from '../data/db/manageDbPool';
const agent = await withRef(manageDbPool, resolvedRef, (db) =>
getFullAgent(db)({
scopes: { tenantId, projectId, agentId },
})
);
Write with auto-commit
await withRef(
manageDbPool,
resolvedRef,
async (db) => {
await updateAgent(db, agentId, data);
},
{ commit: true, commitMessage: 'Update agent config' }
);
Batching operations
Batch multiple operations in a single withRef to use one connection and one checkout:
const result = await withRef(
manageDbPool,
resolvedRef,
async (db) => {
await createCredential(db, credData);
await updateTool(db, toolId, { credentialId });
return { success: true };
},
{
commit: true,
commitMessage: 'Link credential to tool',
author: { name: 'oauth-flow', email: 'oauth@inkeep.com' },
}
);
Rules
withRefacquires, scopes, and releases the connection — don't manage connections yourself- For reads, omit the options (no
commitneeded) - For writes, pass
{ commit: true }with an appropriatecommitMessage - On failure, if
commit: true, uncommitted changes are automatically reset
Obtaining a resolvedRef
Most code paths already have a resolvedRef available:
- Hono routes:
c.get('resolvedRef')(set by ref middleware) - Agent runtime:
this.executionContext.resolvedRef - Service params: passed as a function parameter
If you need to resolve a branch ref manually:
import { getProjectScopedRef, resolveRef } from '@inkeep/agents-core';
const projectScopedRef = getProjectScopedRef(tenantId, projectId, 'main');
const resolvedRef = await resolveRef(agentsManageDbClient)(projectScopedRef);
The ResolvedRef type has three fields:
type ResolvedRef = {
type: 'branch' | 'tag' | 'commit';
name: string; // e.g. "acme_proj_123_main"
hash: string; // commit hash
};
Key Files
| File | Purpose |
|---|---|
agents-api/src/middleware/branchScopedDb.ts |
Middleware for /manage routes |
packages/agents-core/src/dolt/ref-scope.ts |
withRef wrapper and nesting detection |
packages/agents-core/src/dolt/ref-middleware.ts |
Ref resolution middleware (resolves ref query param) |
packages/agents-core/src/dolt/ref-helpers.ts |
Helper functions (getProjectScopedRef, resolveProjectMainRef) |
packages/agents-core/src/validation/dolt-schemas.ts |
ResolvedRef type and Zod schemas |
agents-api/src/data/db/manageDbPool.ts |
Connection pool singleton |
agents-api/src/data/db/manageDbClient.ts |
Global Drizzle client (don't use directly in scoped contexts) |