Coding agent snapshot
Laptop recipe: install the CLI, bind a token to your local agent, and have a coding agent snapshot the database before Hibernate auto-DDL or a migration changes it.
Role: Developer laptop + coding agent Β· CLI: quemsi snapshot (--wait is the default)
This is not CI. Pipelines use Snapshot before deploy. Clicks in the console: Snapshot before a schema change. Any coding agent can run the same CLI; Cursor is the worked example below.
Before you start
- A local Quemsi agent is ONLINE and this database is a data item on Data.
- You know the data name and the local agent name.
- If that data has more than one forward (backup) flow on the agent, you must pass
--flow(the flow name). One flow: omit it.
Steps
Install the CLI
Download from /cli-releases/latest/. Put the binary on PATH. On Windows the file is quemsi.exe; the command is still quemsi.
Linux:
curl -fsSL -o quemsi https://quemsi.com/cli-releases/latest/quemsi && chmod +x quemsi && sudo mv quemsi /usr/local/bin/quemsi
Windows: download quemsi.exe and add it to PATH.
JAR (Java 21), either OS:
curl -fsSL -o quemsi.jar https://quemsi.com/cli-releases/latest/quemsi.jar
java -jar quemsi.jar snapshot --data β¦ --agent β¦
Create a laptop token
Open Company Setup β API tokens. Name it something like cursor-local. Bind it to your local agent. Scopes: snapshot and read only β not restore. See Create API tokens.
Put the secret in your shell profile or Cursor environment. Do not commit it.
export QUEMSI_TOKEN=qsk_...
# QUEMSI_URL defaults to https://quemsi.com
Snapshot before the schema changes
--wait is the default. Do not start the app, tests, or a migrate command until this exits 0.
quemsi snapshot --data YOUR_DATA --agent YOUR_LOCAL_AGENT \
--tag work=baseline --tag purpose=pre-schema \
--descript "pre-schema snapshot"
Use a distinct tag such as work=baseline. Restore lists the latest snapshot per tag combination. Do not reuse a nightly tag.
When to snapshot
Quemsi does not run your migration. Snapshot at the moment before the database schema changes. That moment depends on how you apply DDL.
Hibernate ddl-auto=update
There is no migrate CLI. Hibernate applies schema on the next app start (spring-boot:run, bootRun, tests that boot JPA, or Run/Debug in the IDE).
Snapshot after you edit entity / mapping files, before that boot. A hook that only watches Flyway or Liquibase will miss this.
Flyway, Liquibase, or SQL
Snapshot before the migrate command. Gate that command so it does not run if quemsi snapshot fails.
Cursor: rule plus hook
A rule tells the agent to snapshot first. The agent may skip it. A project hook is what actually fires. Commit the hook files; keep QUEMSI_TOKEN in user env.
Cursorβs afterFileEdit matcher is a tool type such as Write, not a file glob. Filter entity or migration paths in the script. afterFileEdit runs after the write; the snapshot still happens before the next boot. beforeShellExecution is what blocks migrate or bootRun if the snapshot fails. Matchers on that event are JavaScript-style regexes on the command string.
Rule (advisory)
Before applying a schema change β Hibernate auto-DDL on next boot, or a migrate command β run quemsi snapshot with work=baseline and purpose=pre-schema and wait for exit 0. Do not restore unless the person asks.
Project hook
Save as .cursor/hooks.json at the project root. Set failClosed so a failed snapshot (agent offline, missing token) blocks the edit or migrate.
{
"version": 1,
"hooks": {
"afterFileEdit": [
{
"command": ".cursor/hooks/quemsi-snapshot.sh",
"matcher": "Write|TabWrite",
"failClosed": true
}
],
"beforeShellExecution": [
{
"command": ".cursor/hooks/quemsi-snapshot.sh",
"matcher": "flyway|liquibase|migrate|spring-boot:run|bootRun",
"failClosed": true
}
]
}
}
Save the script as .cursor/hooks/quemsi-snapshot.sh, make it executable, and replace YOUR_DATA / YOUR_LOCAL_AGENT. It needs quemsi and jq on PATH. It reads JSON on stdin. For file edits it snapshots only when the path looks like an entity or a migration. For shell it snapshots, then allows the command only if the snapshot exits 0.
#!/usr/bin/env bash
set -euo pipefail
input=$(cat)
file=$(printf '%s' "$input" | jq -r '.file_path // .path // empty')
command=$(printf '%s' "$input" | jq -r '.command // empty')
needs_snapshot=0
if [[ -n "$file" && "$file" =~ (entity|Entity\.java|/db/migration/|liquibase|flyway) ]]; then
needs_snapshot=1
fi
if [[ -n "$command" && "$command" =~ (flyway|liquibase|migrate|spring-boot:run|bootRun) ]]; then
needs_snapshot=1
fi
if [[ "$needs_snapshot" -eq 0 ]]; then
if [[ -n "$command" ]]; then
echo '{ "permission": "allow" }'
fi
exit 0
fi
quemsi snapshot --data YOUR_DATA --agent YOUR_LOCAL_AGENT \
--tag work=baseline --tag purpose=pre-schema \
--descript "pre-schema snapshot"
if [[ -n "$command" ]]; then
echo '{ "permission": "allow" }'
fi
exit 0
Do not match every mvn test unless you want a snapshot on each test run. Do not put QUEMSI_TOKEN in the repo.
Restore is a person
If the schema change goes wrong, overwrite back from the UI: Restore a tagged snapshot, filter to work=baseline. Or run an explicit quemsi restore yourself. Do not auto-restore from the coding agent. Restore overwrites the target database.
Gaps
- IDE Run/Debug does not go through Cursor hooks. If you edit entities in Cursor, the file-edit hook still snapshots before you hit Run in the IDE. Edits made only in the IDE are not hooked β snapshot yourself or from the UI.
- If the token is missing or the agent is offline,
quemsi snapshotfails. WithfailClosed: true, Cursor blocks the matched action. That is the intended safety net. ambiguous-flowβ pass--flowwith the forward flow name.no-forward-flowβ create a backup flow in the UI first.
Not this page
- Clicks on Take Snapshot β Snapshot before a schema change.
- CI snapshot before a release β Snapshot before deploy.
- CI restore before tests β Restore before tests.
Token, then snapshot
Bind a laptop token to your local agent, install quemsi, snapshot before Hibernate or a migration.