PluginsModsTest a mod

Test a mod

A mod is an ordinary program that reads JSON lines and writes JSON lines. That makes it easy to test without starting Syntic Code at all: feed it the messages a session would send, and check what it writes back. Once the program behaves, enable it and try it in a real session.

This page covers three levels of testing:

  1. Check the manifest.
  2. Drive the program by hand or from a script.
  3. Try it in a live session.

Check the manifest

syntic mod list reads every folder in ~/.syntic/mods/ and validates its mod.json:

syntic mod list
Mods in /home/sam/.syntic/mods
  turn-clock 0.1.0  [off]  Footer clock for the current turn and a pane with recent turn times
  pr-pane  [broken]
      mod.json names `pr-panel` but the folder is `pr-pane`

A [broken] mod is never started. The line under it says why. Common reasons are covered in Troubleshoot a mod.

syntic mod enable <name> goes one step further: it also checks that the program in command can be found. A relative path must exist inside the mod folder; a bare name must be found on the cleaned PATH.

Folders whose name is not a valid mod name (for example My_Mod), and folders without a mod.json, are skipped silently by syntic mod list. If your mod is missing from the list entirely, check the folder name first.

Drive the program by hand

Run the program from its folder and type messages yourself. Start with hello, then send events:

cd ~/.syntic/mods/turn-clock
sh run.sh

Paste these lines one at a time:

{"type":"hello","protocol":1,"mod":"turn-clock","events":["turn.start","turn.end"],"ui":["status","pane"],"granted":["notes"]}
{"type":"event","event":"turn.start","data":{"turn":1}}
{"type":"event","event":"turn.end","data":{"turn":1,"seconds":130}}
{"type":"bye"}

You should see the mod’s replies right after each line, for example:

{"type":"draw","slot":"status","text":"turn clock ready"}
{"type":"draw","slot":"status","text":"turn 1 running"}
{"type":"draw","slot":"status","text":"turn 1 took 130s"}
{"type":"draw","slot":"pane","title":"Turn times","lines":["turn 1: 130s"]}
{"type":"call","id":1,"method":"note.post","params":{"text":"Turn 1 took 130s."}}

If a reply only shows up after you press Ctrl+D, your program is buffering its output. Flush after every line.

Script a test

Put the input in a file and check the output with any tool you like. This example uses jq to make sure every output line is valid JSON with a known type:

cat > /tmp/turn-clock.in <<'EOF'
{"type":"hello","protocol":1,"mod":"turn-clock","events":["turn.start","turn.end"],"ui":["status","pane"],"granted":["notes"]}
{"type":"event","event":"turn.start","data":{"turn":1}}
{"type":"event","event":"turn.end","data":{"turn":1,"seconds":7}}
{"type":"bye"}
EOF
 
sh run.sh < /tmp/turn-clock.in > /tmp/turn-clock.out
jq -e 'select(.type != "draw" and .type != "call" and .type != "subscribe")' /tmp/turn-clock.out \
  && echo "unexpected message type" || echo "all lines ok"
grep -c '"slot":"pane"' /tmp/turn-clock.out

Things worth testing:

CaseInput to sendWhat to expect
Normal starthello with all grantsA first draw, if the mod shows something at start
Missing granthello with "granted":[]No call to methods that need a permission
Unknown fieldsan event with extra keys in dataNo crash; extra keys ignored
Missing fieldsturn.end without secondsA sensible fallback, not a crash
Error results{"type":"result","id":1,"ok":false,"error":"too many notes; try again in a minute"}The mod keeps running
ShutdownbyeThe program exits quickly (under half a second)
End of inputclose standard input without byeThe program exits

Also check the size of what you draw. Text over the slot limits is cut with an ellipsis, which may hide the part you care about. See Screen areas for the limits.

Match the real environment

In a session, a mod starts with almost no environment variables and runs in its own folder. A mod that works in your shell may fail there because it relied on a variable or a tool from a project folder. Reproduce the real start-up on Unix with env -i:

cd ~/.syntic/mods/turn-clock
env -i HOME="$HOME" PATH=/usr/bin:/bin \
  SYNTIC_MOD_NAME=turn-clock \
  SYNTIC_MOD_DIR="$PWD" \
  SYNTIC_MOD_DATA="$HOME/.syntic/mod-data/turn-clock" \
  SYNTIC_MOD_PROTOCOL=1 \
  sh run.sh < /tmp/turn-clock.in

The real PATH is your own PATH with unsafe entries removed (relative folders, missing folders and anything inside the opened project), plus standard system folders. The full list of variables is on the Mod API page.

Try it in a live session

Enable the mod

syntic mod enable turn-clock

Start a session

syntic

Mods start right after the session is set up. If a mod fails to start, a warning line in the conversation says so and gives the reason.

Exercise each event

  • Send a prompt to trigger turn.start and turn.end.
  • Change the permission mode to trigger mode.change.
  • Exit the session to trigger session.end and bye.

Check each slot

Widen the terminal to at least 90 columns to see panes. Narrow it to confirm the mod is still useful when panes are hidden.

Log while you debug

Standard error is discarded in a session, so write logs to a file in your data folder:

log() { printf '%s\n' "$*" >> "$SYNTIC_MOD_DATA/debug.log"; }

Then follow it from another terminal:

tail -f ~/.syntic/mod-data/turn-clock/debug.log

Remove or quiet the logging before you share the mod.

Next steps