Center Debugger¶
The Center ships a stop-the-world debugger for server-side AmiScript: timers, triggers, procedures, and methods. It freezes the Center actor thread at a breakpoint and lets you inspect and step from a plain command surface: no IDE, no second JVM, no separate protocol. The same debugger backs the editor experience over DAP; this page is the direct command syntax you drive from MCP tooling or the admin console.
Note
The debugger is enabled by default. Setting ami.db.debug.enabled=false removes it: with the flag off there is zero runtime path, and breakpoints never fire.
Enabling¶
The flag defaults to true. To set it explicitly, use the Center's local.properties:
Restart AmiCore to pick it up. A breakpoint armed while the flag is off is remembered but will not fire until the flag is set and the target is (re)started. The arm command warns when this is the case.
How It Works¶
When execution reaches an armed line, the debugger blocks the Center actor thread in place. It does not unwind. The whole Center freezes at a consistent point, holding the partition write lock, so nothing else mutates state while you inspect. Because the frozen actor holds that lock, normal queries cannot run; instead the debug commands travel a lock-free command pump that the frozen actor services, so status / backtrace / step / resume all work while everything else is paused.
The Center is frozen while paused
A breakpoint hit stops the entire Center, not just one session. Normal queries are rejected with a "locked debug state" message until you resume, continue, or abort. Arm breakpoints deliberately, and use the idle auto-resume safety net.
Issuing Commands¶
The command surface is one string, reachable 3 ways:
| Surface | Form |
|---|---|
| MCP | center_debug(command="<subcommand>") |
| Admin console | center_debug <subcommand> |
| Query | any statement beginning with debug (e.g: debug status) is routed to the debugger instead of the query engine |
All three parse the same vocabulary. The MCP/admin form is lock-free and works while the Center is frozen; the query form cannot pause behind the frozen actor, so prefer center_debug for anything issued during a freeze.
Target IDs¶
A breakpoint names its target with the Center grammar:
The <slot> is the script slot within the object: script for a timer/procedure/method, or the specific handler (onInsertingScript, onUpdatedScript, …) for a trigger.
Command Reference¶
Breakpoints (Armed Any Time, No Freeze Needed)¶
| Command | Effect |
|---|---|
arm <targetId> <line> |
Set a breakpoint at a source line of a target. |
clear <targetId> <line> |
Remove one breakpoint. |
clear <targetId> |
Remove all breakpoints on a target. |
clearall |
Remove every breakpoint. |
status |
Show whether the debugger is enabled, whether it is frozen, and (if frozen) the target, line, and paused statement. |
Inspecting a Frozen Target¶
| Command | Alias | Returns |
|---|---|---|
backtrace |
bt |
The call stack, one row per frame (Frame, Scope, Line, Statement). |
locals [frameId] |
The in-scope variables of a frame (frame 0 = innermost): Name, Type, Value. |
|
eval <expression> |
print, p |
Evaluate an AmiScript expression in the frozen frame's scope (locals visible) e.g: eval x + 1. |
query <sql> |
Run a read-only SELECT against the frozen Center's tables e.g: query SELECT * FROM Orders. |
eval is for a value in the paused scope; query is for the database. Both run without unfreezing.
Advancing Execution (Terminal: They Release the Freeze)¶
| Command | Alias | Effect |
|---|---|---|
step |
next, stepover |
Run any call on this line to completion, stop at the next statement in this target. |
stepin |
into, stepinto |
Descend into a call/method on this line, stop on the callee's first statement. |
stepout |
out, finish |
Run the rest of this target, stop at the caller's next statement. |
resume |
Run to the next breakpoint. | |
continue |
Run to completion, breakpoints disabled for the rest of this run. | |
abort |
Unwind the frozen execution immediately. |
After a step, run status to see the new position.
Coverage¶
coverage startup|shutdown|pause|resume|reset|report [targetId] records line and branch coverage without freezing:
startup: start recording.pause: stop recording and keep the results.resume: start recording again.reset: discard the results and keep recording.shutdown: stop recording and discard the results.report: show the results, or the expressions of one target.
See Code Coverage.
detach¶
An operator escape hatch: an IDE (DAP) attach takes an exclusive controller claim, and a client that dies without releasing it (crash, half-open socket) would otherwise hold the debugger until the Center restarts. detach drops that claim. It is lock-free and safe whether or not the Center is frozen. It releases the claim only, and does not resume the actor.
A Session¶
Idle Auto-Resume¶
A breakpoint that no one is driving cannot freeze the Center forever: after an idle window (ami.db.debug.idle.resume.millis) a frozen-but-untouched breakpoint auto-resumes. This keeps a walked-away debug session, or a controller that vanished, from wedging the deployment.
Single Controller¶
An IDE (DAP) attach takes an exclusive controller claim, so a second attach is refused with a message naming the current holder instead of two editors interleaving steps on one frozen actor. The claim is released when that session detaches, or with detach when the client died without releasing it.
The claim does not lock out this command surface
center_debug keeps working while a DAP session holds the claim. That is deliberate, and it is what makes detach usable when the IDE client is wedged. The consequence is that a step or resume issued here will advance a freeze an attached editor is driving, and the editor will then be showing a position that no longer exists. When someone is attached, either coordinate with them or detach first.
Related¶
- Language and Debug Servers: the LSP/DAP servers that expose this debugger to your editor over the DAP protocol.
- Code Coverage: the
coverageverb and the coverage the debugger records. - Unit Testing: the isolated test runner, which reuses this debugger's per-statement hook to measure coverage.