V Vant Docs

Locks API

Exact signatures for both lock modules. Concepts and operations guidance: Locks.

lib/brain-lock.js - authorization lease

Token- and agent-scoped lease answering “who may write to this brain”. TTL default DEFAULT_TIMEOUT_MS (1 hour). Emits brain-lock:* events.

Export Signature Returns
acquireBrainLock async (agentId?, timeout?, { brain }?) token string, or null if not acquired
releaseBrainLock async (agentId?, token?, { brain }?) { success, message }
brainLockStatus ({ brain }?) { agentId, token, age, valid, stale?, brain } or null
forceReleaseBrainLock ({ brain }?) boolean (true = a lock file was deleted)
getAgentId () agent id (VANT_AGENT_ID or agent-<pid>)
getBrainLock (brain?) brain-scoped internal state
getLayerStatus () { name, type: 'authorization_lease', enabled, trackedBrains, defaultTtlMs }
getStackLockStatus ({ ... }?) { source: 'stack', brains, byBrain }
listStackLocks ({ ... }?) rows: { brain, agentId, token, age, valid }
DEFAULT_TIMEOUT_MS 3600000 the 1h TTL constant
BRAIN_LOCK_CONFIG object attempts, backoff and check-interval tuning

Notes:

lib/lock.js - cross-process mutex

Short-lived advisory lockfile serializing one whole-snapshot write across processes. No identity, no TTL semantics; stale takeover is mtime-based.

Export Signature Returns
acquire (lockPath, { staleMs?, waitMs? }?) { ok, reason }, reason in acquired \| held \| unavailable
release (lockPath) void; only unlinks when the file’s pid is this process
withLock (lockPath, fn, { failMode?, staleMs?, waitMs? }?) Promise; body result, or { ok: false, reason, aborted: true } in fail-closed mode
withLockSync (lockPath, fn, { failMode?, staleMs?, waitMs? }?) fn’s return value, or { ok: false, reason, aborted: true } in fail-closed mode; sync fn required (pass 115)
mutex () { run(fn): Promise, pending: number } in-process chain
stats () observability counters for THIS process (pass 117): acquires, held, unavailable, takeovers, releases, bodiesRun, bodyErrors, aborted, holdMsTotal, holdMsMax, heldNow
pathFor (kind, id?, { brain }?) models/private/<brain>/.locks/<kind>[__<id>].lock
pathForGlobal (kind, id?) models/.locks-global/<kind>[__<id>].lock
DEFAULT_STALE_MS 5000 mtime age for stale takeover
DEFAULT_WAIT_MS 500 bounded wait before reporting held

Notes:

CLI: vant lock

Drives the lease (lib/brain-lock.js). The token from acquire is saved to .lock-brain-token for cross-process release.

Command Description
vant lock acquire [agentId] Acquire the lease; prints and saves the token
vant lock release [token] Token-verified release; exits non-zero and keeps the token file when denied
vant lock status Current brain + whole-stack lease status
vant lock force Force release (admin): deletes the lock file unconditionally

(Short forms acq, rel, stat work. The MCP tool has a separate stack action returning the same whole-stack view status prints.)

MCP tool: vant_lock

Param Type What
action string acquire, release, status, stack, force (the whole-stack view status also prints via CLI)
token string Release token from acquire
agentId string Agent identifier
vant_lock(action="acquire")
vant_lock(action="release", token="<token>")
vant_lock(action="status")
vant_lock(action="stack")
vant_lock(action="force")

Returns { action, acquired, token } on acquire, { action, success, message } on release, { action, status, stack, held } on status/stack, and { action, forceReleased } (boolean) on force. This tool manages the lease; the mutex is a library-level primitive and has no MCP surface.

Where locks live on disk

Path Owner Gitignored
models/private/.locks/.lock-<brain>.json lease yes (.locks/, .lock-brain-token)
models/private/<brain>/.locks/<kind>[__<id>].lock mutex (per-brain) yes
models/.locks-global/<kind>[__<id>].lock mutex (repo-scoped) yes

Leaked lockfiles are scanned by npm run lint:locks (scripts/audit-locks.js), which also asserts the two roots, the no cross-require rule between the modules, and the fail-closed wiring of the guarded writers.