Every plugin command spends 0.4 s before the plugin runs
jp ticket --version takes about 410 ms, where jp --version takes 4 to 7 ms. Every plugin command pays that before the plugin does anything: jp ticket list, jp ticket board, jp -F json ticket show, and jp rfd show all take 380 to 425 ms, for work that takes milliseconds. The site's dev server starts one jp per write, so every drag on the ticket board costs the same.
Measured on 2026-10-21 in JP's own workspace, median of five runs:
| Command | Median |
|---|---|
jp --version | 4 ms |
jp workspace show | 108 ms |
jp config show | 189 ms |
jp ticket --version | 414 ms |
Where the time goes
Not profiled. From the code, before it starts the plugin, jp:
- loads the workspace and its configuration, which the two commands above put at 100 to 190 ms;
- reads every
jp-*binary in its plugin directory and on$PATHin full, to find each one's manifest (discovery::discover_incallsread_manifest, which reads the whole file, for every executable it finds); - computes the SHA-256 of the plugin it is about to run, even when the plugin's configuration says
run = "allow"(admission::admithashes the binary beforedecidelooks at the policy).
Suggested change
Profile first: the configuration load may be the larger share, and it is a separate fix.
For the binaries, cache each one's manifest and SHA-256 in the user-local plugin directory, keyed by canonical path, size, and modification time. A hit skips reading the binary; a miss reads it once and records the result. A rebuilt binary changes its modification time, misses the cache, and is checked against its approval again.
The cache trusts the file's size and modification time. Someone who can rewrite an approved binary and restore both would go unnoticed, where the hash today catches them; weigh that against the trust model in RFD 077 before choosing the key.