Highlights
Pad v0.10.0 is a hardening-and-surface release: a security audit sweep, a big
expansion of the agent/MCP tool surface (v0.9 → v0.14), new web UX foundations,
mobile OAuth sign-in, and a batch of CLI + reliability improvements.
🔒 Security hardening
Driven by the security ecosystem audit (PLAN-1990). Session User-Agent binding
gains an enforce mode (TASK-2056), share-link password verification is now
rate-limited against brute force (TASK-2055), TOTP login codes are single-use
(BUG-2054), webhook HMAC secrets are encrypted at rest and masked in responses
(BUG-2057), the webhook SSRF guard now runs at dial time with a wider deny-list
(#836), and OAuth consent completes when the authorize scope is absent
(BUG-2088). Dependencies moved to Go 1.26.5 with govulncheck in binary mode
plus x-crypto / gRPC security bumps (#896).
🤖 Agent & MCP surface (v0.9 → v0.14)
The MCP tool catalog grew substantially: a read-only pad_attachment surface
(#875), pad_project ready + stale actions (#878), an agent-accessible
activity feed via pad project activity + MCP action (#877), field-level PATCH
with an optimistic-concurrency conflict envelope and read-only item version
history (TASK-2022), summary-shaped item list with --full opt-in and MCP
limit clamps (TASK-2000), and a bootstrap convention_index for
triggered-convention discovery (TASK-2004). Bootstrap now emits compact JSON
for agents (TASK-2021).
🖥️ Web UX foundations
A shared native-dialog Modal primitive with focus trap now backs the form
modals across the app (TASK-2023, plus route-inline and roles-page migrations),
the API client handles 429 / Retry-After with a "server busy" toast
(TASK-2026, TASK-2080), the SSE connection-status indicator renders
(TASK-2027), and the command palette surfaces body-content matches (TASK-2008).
Several route monoliths were broken up (contentSaver / collab-flush extraction).
📱 Mobile OAuth sign-in
OAuth sign-in landed on both mobile shells — iOS via
ASWebAuthenticationSession (TASK-1717) and Android via Custom Tabs deep-link
callback (TASK-1767) — backed by secure token storage and biometric unlock
(TASK-1718).
🛠️ CLI & reliability
New pad item open command (#919), a width-aware item-list table with
STATUS/PRIORITY columns (TASK-2030), claude-code + codex targets for
pad mcp install (TASK-2040), and root usage/error hygiene (TASK-2031).
Under the hood: atomic field + parent-link updates (BUG-2013), parent-link
cycle guards (BUG-2073, BUG-2074), panic recovery on background goroutines,
and dashboard/bootstrap N+1 collapses into set-based queries (BUG-2002,
BUG-2003).
🙏 Thanks to our contributors
Huge thanks to everyone who contributed a PR to this release:
- @molloyzak13 — parent commands now exit non-zero on an unknown subcommand (#861)
- @dchaudhari7177 — migrated the KeyboardShortcuts modal to the shared Modal primitive (#900)
- @cnYui — wrap comment not-found errors with item context (#910)
- @raj921 — added Windows and macOS smoke tests to CI (#911)
- @Rionlyu — added the
pad item opencommand (#919) - @hfl0506 — support the OpenCode install target for
pad agent(#923)
Install
brew install perpetualsoftware/tap/pad
# or pull the container image
docker pull ghcr.io/perpetualsoftware/pad:0.10.0Verifying
Every archive is signed with cosign (keyless / Sigstore OIDC) and ships an
SBOM + SLSA build provenance. As of v0.10.0 the checksums signature ships as a
single Sigstore bundle (checksums.txt.sigstore.json) — verify with:
cosign verify-blob \
--certificate-identity-regexp "^https://github.com/PerpetualSoftware/pad/.github/workflows/release.yml@.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
--bundle ./checksums.txt.sigstore.json \
./checksums.txtChangelog
Features
- feat(cli): add pad item open command (#919)
- feat(security): enforce session UA binding under strict mode (TASK-2056) (#912)
- feat(cli): add claude-code + codex targets to pad mcp install (TASK-2040) (#909)
- feat(cli): width-aware item-list table with STATUS/PRIORITY columns (#894)
- feat(web): surface rate_limited errors as a server-busy toast (TASK-2080) (#888)
- feat(web): 429/Retry-After handling in API client (TASK-2026) (#882)
- feat(web): shared native-dialog Modal primitive + migrate form modals (TASK-2023) (#881)
- feat(items): field-level PATCH + conflict envelope + read-only version history (TASK-2022) (#876)
- feat(mcp): expose pad_project ready + stale actions (#878)
- feat(project): agent-accessible activity feed (pad project activity + MCP action) (#877)
- feat(mcp): add read-only attachments surface (pad_attachment) (#875)
- feat(editor): add "Attach file" to the block context menu (TASK-2067) (#862)
- feat(editor): add explicit attach-file button to tiptap menu (TASK-2067) (#860)
- feat(bootstrap): add convention_index for triggered-convention discovery (TASK-2004) (#848)
- feat(store): guard against schema-ahead downgrade + pre-migration snapshot + upgrade docs (TASK-2006) (#843)
- feat(cli,mcp): summary-shaped item list with --full opt-in + limit clamp (TASK-2000) (#842)
- feat(web): surface body-content matches in command palette (TASK-2008) (#839)
Bug fixes
- fix(release): migrate cosign signing to v3 bundle format (BUG-2091) (#925)
- fix(agent): support OpenCode install target (#923)
- fix(e2e): disable rate limiting on the E2E server to stop 429 flakes (BUG-2089) (#922)
- fix(oauth): default absent authorize scope so consent completes (BUG-2088) (#921)
- fix(cli): wrap comment not-found errors (#910)
- fix(security): encrypt webhook HMAC secrets at rest, mask in responses (BUG-2057) (#915)
- fix(security): make TOTP login codes single-use (BUG-2054) (#914)
- fix(security): rate-limit share-link password verification (TASK-2055) (#913)
- fix(ci): let Go fetch the 1.26.5 toolchain go.mod pins (unbreak CI) (#901)
- fix(cli): root usage/error/format hygiene (TASK-2031, BUG-2032) (#893)
- fix(web): distinguish transient failures from not-found (BUG-2025) (#884)
- fix(web): flush pending raw-markdown on unload (BUG-2024) (#883)
- fix(web): render SSE connection-status indicator (TASK-2027) (#880)
- fix: parent commands exit non-zero on unknown subcommand (#850)
- fix(playbooks): enforce draft gate server-side + expose status (BUG-2020) (#874)
- fix(store): workspace-level guard for N-hop parent cycles (BUG-2074) (#871)
- fix(store): close parent-link cycle & stale-old-parent TOCTOU races (BUG-2073) (#870)
- fix(server): guard degraded/degraded_sections in bootstrap dashboard (BUG-2072) (#869)
- fix(store): make item field + parent-link update atomic (BUG-2013) (#868)
- fix(webhooks): track delivery goroutines + bounded retry (BUG-2012) (#864)
- fix(server): surface dashboard sub-query failures instead of silent empty sections (BUG-2014) (#867)
- fix(server): add panic recovery to background sweeper goroutines (BUG-2071) (#865)
- fix(server): add panic recovery to goAsync background tasks (#863)
- fix(mobile): hide bottom nav when on-screen keyboard is up (BUG-2070) (#859)
- fix(server,cli,mcp): default item list to per-collection non-terminal filter (BUG-2001) (#845)
- fix(mcp): sync tool-surface docs to v0.9 after item-list default bump (#844)
- fix(web): exact-pin coordinated Tiptap packages + CI drift guard (BUG-2009) (#838)
- fix(webhooks): enforce SSRF guard at dial time + widen deny-list (#836)
- fix(cli): safe SQLite db backup/restore (config path + VACUUM INTO) (#837)
Performance
- perf(bootstrap): compact JSON for agents; trim SKILL.md reference sections (#873)
- perf(server): collapse dashboard/bootstrap N+1 into set-based queries (BUG-2002) (#847)
- perf(store): batch parent-lineage enrichment into one scoped query (BUG-2003) (#846)
Refactors
- refactor(web): migrate KeyboardShortcuts modal to shared Modal primitive (#900)
- refactor(web): migrate roles page dialogs to shared Modal primitive (#891)
- refactor(web): migrate remaining route-inline modals to shared Modal primitive (TASK-2083) (#890)
- refactor(web): extract collab-flush path from item-detail monolith (TASK-2082) (#889)
- refactor(web): unify mobile breakpoint into one shared isMobile store (TASK-2028) (#886)
- refactor(web): extract contentSaver + shared progress-merge from item/collection monoliths (TASK-2029) (#885)
- refactor(mcp): make pad_plan/ideate/retro prompt bodies surface-neutral (#872)
- refactor(cli): split cmd/pad/main.go by resource (TASK-2015) (#866)
Other changes
- build(deps): govulncheck binary mode + Go 1.26.5 / x-crypto / gRPC security bumps (#896)
Full Changelog: v0.9.2...v0.10.0