* fix(plugin): session start runs nothing; presence and the arm check wait for the first use of Pad (TASK-3970)
Dave: "the plugin should not be doing anything when a session is started."
session.start now only registers /pad-pane and restores the pane. It no
longer runs `pad session register` / `should-arm`, no longer spawns
pad-monitor.sh, and no longer starts the 5s refresh timer, which now runs
only while the pane is open.
wake() runs once per session, on the first pad Bash command, a Pad MCP tool
call, or opening the pane. The first pad command waits for registration
(never for should-arm), because register mints the worker id that leases key
on. A .pad.toml push.auto_arm opt-in is therefore read at first use.
Tests: session start runs no process and asks for no timer; non-pad Bash
wakes nothing; wake runs once; an MCP tool wakes it; registration happens
before the first pad command runs. Prose swept (skill, monitor script,
CLAUDE.md, registry comments); docs/plugin-releases.md gets the stuck-0.3.x
remedy.
Claude-Session: https://claude.ai/code/session_01EZ6hZzQiytCeBxXrtCWcVd
* fix(plugin): a pad command inside a shell string or after an assignment wakes the session (TASK-3970)
Hunter r1 F1: `bash -c "pad ..."`, `sh -c 'pad ...'` and `X=... pad` missed
the first-use match, so that call ran before presence was recorded. The
class now takes quotes and `=`; a false positive only wakes early.
Claude-Session: https://claude.ai/code/session_01EZ6hZzQiytCeBxXrtCWcVd
* fix(plugin): pad as a whole word, checked against a table of shapes (TASK-3970)
Round r2 found two more missed shapes (Codex: `\pad ...`; hunter: a bare
`pad` before a quote, `)` or `;`). Rather than add a third case, the match
is now `pad` as a whole word, not inside a longer name. watch.test.ts
tables 25 shapes that run pad and 8 that do not, and asserts that
registration ran before each matching command reached the tool
(Codex r2 note).
Claude-Session: https://claude.ai/code/session_01EZ6hZzQiytCeBxXrtCWcVd
* fix(plugin): a Pad MCP tool wakes the session whatever the server is called (TASK-3970)
Codex r3: the matcher required "pad" in the server part of the tool name,
so a Pad server registered under another name (work-tracker) was missed.
It now matches any mcp__<server>__pad_* tool. The tests table Pad tools
under four server names and four tools that are not Pad's, and add ./pad
and ../bin/pad to the Bash shapes.
Claude-Session: https://claude.ai/code/session_01EZ6hZzQiytCeBxXrtCWcVd
* fix(plugin): the pane refreshes after a Pad MCP edit under any server name (TASK-3970)
Hunter r4: the pane-refresh matcher still required "pad" in the server
name, so it disagreed with the wake matcher fixed in 25c39f2aa. Both now
take any server. The wake matcher also allows digits in the tool part.
New pane test.
Claude-Session: https://claude.ai/code/session_01EZ6hZzQiytCeBxXrtCWcVd
* docs(plugin): the file header describes session start and wake (TASK-3970)
Codex r5 nit: the header still said the mod only listens until /pad-pane
runs. Comment-only.
Claude-Session: https://claude.ai/code/session_01EZ6hZzQiytCeBxXrtCWcVd
3.4 KiB
The Claude Code plugin follows stable releases
/plugin marketplace add PerpetualSoftware/pad reads .claude-plugin/marketplace.json on main. Since TASK-3487 its pad entry is pinned to a stable release tag:
"source": {
"source": "git-subdir",
"url": "https://github.com/PerpetualSoftware/pad.git",
"path": "plugin",
"ref": "v0.18.0"
}
so users get the plugin as of that release, not as of main. The url is the full https URL on purpose: Claude Code clones the owner/repo shorthand over SSH, which fails for anyone without a GitHub SSH key. Until the first stable tag that carries an unpinned plugin/ (v0.18.0), the entry stays "./plugin"; pinning to an older tag would hand everyone a plugin that pins version: 0.3.3 and predates the pane.
How the pin moves
The release workflow's pin-plugin job runs after a stable tag's release (vX.Y.Z, never -rc.N) and calls scripts/pin-plugin-marketplace.sh --push <tag>, which rewrites only the entry's source and pushes to main. Users pick it up on /plugin marketplace update or auto-update: with no version field, Claude Code versions a git-subdir plugin by its commit, so a new ref is a new version.
Stable only, because the Homebrew cask never receives an rc: plugin vX pairs with CLI vX. Against an older CLI, the pane keeps working (it uses long-standing commands, with an MCP fallback), and the pad skill tells the user to upgrade when the CLI refuses a command.
If the push fails, the job does not fail the release. It warns and opens an issue; pin by hand from an up-to-date main:
scripts/pin-plugin-marketplace.sh --push v0.18.0
Tracking main on purpose (maintainers)
Once the pin lands, an install from the marketplace is on the last stable release. To run the plugin as it is on your checkout instead:
- One session:
claude --plugin-dir /path/to/pad/plugin. It loads in place, so edits take effect on/reload-plugins, and it takes precedence over an installedpad@padof the same name. - Every session: export
CLAUDE_CODE_PLUGIN_DIRS=/path/to/pad/pluginin your shell profile. It is--plugin-dir's environment form: the plugin loads in place aspad@inlineand takes precedence over the installedpad@pad. Unset it to return to the stable install.
Adding your checkout as a local marketplace does not track your working tree: that checkout's own marketplace.json is pinned too, so it installs the tag.
Installs stuck on 0.3.x
Before BUG-3463, the plugin's manifest pinned version: 0.3.3. An install made then is recorded at that version string, and auto-update has been seen to leave it there after the pin was dropped. On 2026-10-19, one machine was still on 0.3.3, installed 2026-09-01, so every session started its old always-on monitor and opened with Monitor "Pad item events…" ended without producing output (TASK-3970). One command moves it forward:
claude plugin update pad@pad
claude plugin list shows the installed version. A version that is a commit (d8dedc09b904-…) follows the marketplace pin; 0.3.3 does not. We have not yet found a way to move such an install from the marketplace side.
Since TASK-3970 the plugin does nothing at session start: no CLI call, no monitor, no timer. Presence registration and the arm check run on the session's first use of Pad (a pad command, a Pad MCP tool, or opening the pane).