mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-09-23 02:53:31 +00:00
714da48442d68e29c1a730be39b43601bf69964a
34 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
de8679f535 |
chore(mcp): bump ToolSurfaceVersion 0.3 → 0.4; document v0.4 envelope (TASK-1418) (#544)
* chore(mcp): bump ToolSurfaceVersion 0.3 → 0.4; document v0.4 envelope (TASK-1418)
Final PR of PLAN-1410. The contractual announcement that the v0.4
bootstrap shape is stable.
## What
1. internal/mcp/version.go — ToolSurfaceVersion: "0.3" → "0.4".
The godoc on the constant gains a full v0.4 changelog entry
enumerating each shape change shipped by PLAN-1410's six
bootstrap PRs:
- BootstrapCollection projection (TASK-1412): drops id,
workspace_id, created_at, updated_at, settings; schema as
a nested JSON object.
- BootstrapRole projection (TASK-1423): drops id,
workspace_id, tools, created_at, updated_at.
- Convention slug dropped (TASK-1413).
- Top-level recent_activity duplicate removed (TASK-1413).
- BootstrapDashboard wrapper caps five sub-arrays (TASK-1413
+ TASK-1422): attention, recent_activity, active_items,
active_plans, by_role at 5 entries each, parallel
*_overflow_count fields. suggested_next deliberately
excluded — already capped to 3 upstream.
- Schema label omitted when label == TitleCase(key) (TASK-1424).
Plus an explicit compatibility note: all v0.4 changes are
additive or subtractive (no field renames); clients that read
the preserved field names keep working unchanged.
2. CLAUDE.md updates:
- "## MCP server" header: v0.3 catalog → v0.4 catalog, with a
one-paragraph summary of what v0.4 shipped.
- "Surface:" Tools bullet: v0.3 → v0.4, with a note that the
tool/action surface is unchanged — only the bootstrap JSON
these tools return has been trimmed.
- "Stability contract": ToolSurfaceVersion (currently "0.4"),
comprehensive single-paragraph description of the v0.4
envelope, cumulative size reduction (40% live / 54% fixture),
and explicit additive/subtractive note.
## Why the strategy worked
PLAN-1410's "version bump last" strategy paid off:
- Each individual shape PR (TASK-1412/1413/1422/1423/1424) was
reviewable in isolation against a stable v0.3 contract.
- The six skill-side PRs (TASK-1414/1415/1416) had no MCP-shape
impact and didn't need any version bump consideration.
- v0.4 is now announced as a single comprehensive contract change,
not five separate version bumps — easier for downstream MCP
consumers (Claude Desktop, Cursor, future Pad Cloud remote MCP)
to reason about.
## Verification
- `make check` — golangci-lint 0 issues, all Go tests pass
(including the version-tracking tests in catalog_meta_test.go
that auto-pin to whatever ToolSurfaceVersion is set to),
govulncheck clean, web build clean.
- MCP handshake (verified via `pad mcp serve` + an initialize
JSON-RPC request) advertises
capabilities.experimental.padToolSurface.version = "0.4".
padCmdhelp.version stays at "0.1" as expected.
## Post-merge follow-ups
After this lands:
- Update PLAN-1410's Result section with a "v0.4 announced" line
and the final post-everything measurement (taken against
docapp after `make install`).
- Flip PLAN-1410 status from `active` → `completed`.
These are pad-item operations, not git changes.
Parent: PLAN-1410. Closes the plan.
* fix(mcp): update stale v0.3 references after ToolSurfaceVersion bump (TASK-1418 follow-up)
Address Codex P2 + P3 findings on PR #544: bumping
ToolSurfaceVersion in version.go left four runtime/user-facing
docs still claiming v0.3:
P2 — runtime MCP docs:
- internal/mcp/instructions.md "## Tool surface (v0.3)" → v0.4
- internal/mcp/catalog_meta.go "v0.3 server-introspection tool" → "(v0.4 catalog)"
- internal/mcp/catalog_meta.go padMetaToolDescription twice:
* "the v0.3 tool catalog" → "the v0.4 tool catalog"
* "v0.3 catalog dump" → "v0.4 catalog dump"
- internal/mcp/catalog_meta.go actionMetaToolSurface godoc:
"v0.3 catalog" → "catalog" (de-versioned; the comment is
about scope, not version)
P3 — public README:
- README.md "Tool catalog (v0.3)" → "Tool catalog (v0.4)"
- README.md "tool_surface_version: '0.3'" → "'0.4'" with a
pointer to PLAN-1410's bootstrap-trim summary and
version.go's full v0.4 changelog.
Without these, agents reading the initialize-instructions blob or
pad_meta's tool description (both of which are part of the
runtime MCP surface, not just internal docs) would see v0.3 while
the handshake / pad_meta.action: version returned v0.4 — the
exact "contradictory metadata depending on what you read" failure
mode Codex flagged.
Same skill-↔-code sync pattern that has been a running theme
through PLAN-1410's review loops. The cluster of stale references
is a classic side effect of a version bump landing late in a
plan — the version constant is one string, but downstream prose
that names it lives in multiple places.
Verified no remaining "v0.3" claims that imply currency — `grep -rn
"v0\.3\|tool_surface_version" --include="*.{go,md}"` returns only
historical-context mentions in changelog godocs (correct) and the
runtime constant readback (correctly returns "0.4" now).
Parent: PLAN-1410 / TASK-1418.
* fix(mcp): correct schema-type-change disclosure + stale cmdhelp-walker description (TASK-1418 follow-up)
Address Codex round 2 P3 findings on PR #544:
## P3 — `cmd/pad/mcp.go` still described the retired leaf walker
The `pad mcp serve` command's Long description said "every leaf
command becomes an MCP tool, except the curated allow-list
exclusions" — that was true under v0.1 but the cmdhelp leaf
walker was retired in TASK-981 (PLAN-969's v0.2 rollout). The
v0.2/v0.3/v0.4 surface has always been the hand-curated catalog
of eight resource × action tools + pad_set_workspace.
Updated the Long description to:
- Name the v0.4 catalog explicitly.
- List the eight resource × action tools.
- Note that cmdhelp v0.1 still drives per-command arg schemas
at dispatch time (so it's not gone, just no longer drives
tool naming/count).
- Reference TASK-981 for the cutover.
## P3 — "additive/subtractive only" was misleading
The compatibility note in `version.go` and `CLAUDE.md` claimed
all v0.4 changes were additive or subtractive. That glossed over
one breaking change in TASK-1412: `collections[].schema` went
from a JSON-encoded string ("schema":"{\"fields\":...}") to a
nested JSON object ("schema":{"fields":...}). For any v0.3
consumer that read schema as a string and JSON.parse()'d it
themselves, that's a TYPE change, not a no-op.
Updated both godoc and CLAUDE.md to explicitly call this out
as the one breaking change, separately from the additive/
subtractive bucket. Better for downstream MCP consumers to see
the truth than to discover it via runtime failure.
The remaining v0.4 changes ARE additive (overflow counts on
BootstrapDashboard) or subtractive (dropped fields with named
canonical alternatives) — those parts of the original note
are accurate and kept.
Honesty about compatibility is more valuable than a tidy
narrative. Surfaced explicitly in the godoc + the public
contract doc; PLAN-1410's Result section was already honest
about the field-level deltas.
Parent: PLAN-1410 / TASK-1418.
|
||
|
|
9764b2fe92 |
docs: document playbook invocation surface (TASK-1387) (#525)
* docs: document playbook invocation surface (TASK-1387)
Closes out PLAN-1377 — Make Playbooks first-class invokable procedures —
by bringing the four user-facing docs surfaces up to date with the
shipped invocation model. The pad-web docs ship in a separate commit
(../pad-web@main: docs: document playbook invocation surface).
- CLAUDE.md — new Playbooks section after Data Model covering the
three invocation surfaces, the invocation_slug/arguments schema
fields, bootstrap-returns-metadata, the seeded ship playbook, the
web UI editor, and a code map. MCP section grows pad_playbook,
pad://workspace/{ws}/bootstrap, and the pad_set_workspace embedded
response note.
- skills/pad/SKILL.md — adds a "Creating a playbook" subsection under
natural-language routing with CLI examples for trigger-only and
slug-invocable playbooks, plus a Playbooks block in the CLI
reference (pad playbook list/show/run with parsing rules).
- README.md — one-line bump in the feature list mentioning the new
/pad <slug> invocation form and the seeded ship playbook.
Parent: PLAN-1377.
* fix(docs): correct bootstrap route + CLI arguments authoring per Codex review (round 1)
Codex round 1 findings:
[P2] CLAUDE.md cited GET /api/v1/workspaces/{ws}/bootstrap but the
implemented route is /api/v1/workspaces/{ws}/agent/bootstrap (server.go
line 1182). Documented endpoint would 404 for HTTP integrators.
[P2] SKILL.md '--field arguments=[...]' example would fail validation
— pad item create stores all --field values as strings, while
arguments is a json field type. Rewrote the slug-invocable-playbook
authoring guidance to direct agents at the web UI editor for
structured argument authoring (the canonical path the editor was
built for) with the CLI handling everything else. Same fix applied
to the pad-web /docs/agent-integration page in a separate
../pad-web@main commit.
Parent: TASK-1387 / PLAN-1377.
* fix(docs): use full /{username}/{workspace}/playbooks route in SKILL.md per Codex review (round 2)
Codex round 2 finding:
[P3] SKILL.md's recommended web editor path was '/{workspace}/playbooks',
but the SvelteKit route is '/{username}/{workspace}/playbooks'. The
prior path would 404 or land on the wrong workspace. Fixed.
The pad-web docs ship the matching fix in a separate commit at
../pad-web@main: docs(playbooks): use full /{username}/{workspace}
route path per review.
Parent: TASK-1387 / PLAN-1377.
* fix(docs): bump CLAUDE.md MCP tool surface to v0.3 + close SKILL.md backtick per Codex review (round 3)
Codex round 3 findings:
[P2] CLAUDE.md still labelled the tool surface as v0.2; internal/mcp/
version.go advertises ToolSurfaceVersion = '0.3' (since PLAN-1377 /
TASK-1380). Updated to v0.3 and added a note about what v0.3 introduced
(pad_meta.action: bootstrap, pad_set_workspace embedded-bootstrap
response, pad://workspace/{ws}/bootstrap resource).
[P3] SKILL.md's web-editor route had the parenthetical inside the
code span: '`/{username}/{workspace}/playbooks (click "+ New
Playbook")`' — closed the backtick after '/playbooks' so the
rendered code span is the literal path.
The pad-web docs ship the matching v0.3 bump in a separate commit at
../pad-web@main: docs(mcp/tools): bump tool surface to v0.3.
Parent: TASK-1387 / PLAN-1377.
* fix(docs): bump stale MCP catalog references to v0.3 per Codex review (round 4)
Codex round 4 finding [P2]:
Three places still described the MCP catalog as v0.2, contradicting the
v0.3 surface block that landed in this PR:
- CLAUDE.md 'MCP server' lede paragraph — bumped to v0.3, added
pad_playbook to the listed tools, and noted what v0.3 introduced.
- skills/pad/SKILL.md MCP note for MCP-using agents — bumped to v0.3,
added pad_playbook to the listed tools and called out the playbook
invocation surface + bootstrap action.
- README.md 'Tool catalog (v0.2)' block — bumped to v0.3, added the
pad_playbook row, the pad_meta.action: bootstrap row, the bootstrap
resource, and bumped tool_surface_version.
Parent: TASK-1387 / PLAN-1377.
* fix(docs): bump MCP server-side self-description to v0.3 per Codex review (round 5)
Codex round 5 finding [P2]:
Two MCP-server-internal documentation surfaces still advertised v0.2:
- internal/mcp/instructions.md — the markdown blob the server returns
to MCP clients as initialization instructions. Updated 'Tool surface
(v0.2) / Eight tools' to 'Tool surface (v0.3) / Nine tools', added
pad_playbook with list/get/run, added bootstrap to pad_meta's actions,
noted pad_set_workspace's embedded-bootstrap response, and added
pad://workspace/{ws}/bootstrap to the resource list.
- internal/mcp/catalog_meta.go — the pad_meta tool's Description string
said 'v0.2 tool catalog' twice. Bumped both to v0.3.
These ship inside the binary; MCP clients read them directly so v0.2
mentions there contradict the v0.3 catalog the handshake actually
advertises (ToolSurfaceVersion in version.go).
Parent: TASK-1387 / PLAN-1377.
* fix(docs): finish MCP self-description v0.3 cleanup per Codex review (round 6)
Codex round 6 findings [P3]:
[1] catalog_meta.go's padMetaTool block-comment said 'Three actions,
all handled inline' even though bootstrap (the v0.3 fourth action)
dispatches through env.Dispatch. Fixed both the count and the
dispatch description, added the bootstrap row to the action list.
Also corrected the v0.2 mentions in actionMetaToolSurface's comment
and removed the rollout-era language now that the cmdhelp walker is
retired.
[2] instructions.md said 'Nine tools, each with an action enum' but
pad_set_workspace doesn't take an action. Clarified the count as
'eight resource × action tools, plus pad_set_workspace (which takes
a workspace slug only)' and scoped the 'Always pass action' rule to
the eight resource × action tools.
Parent: TASK-1387 / PLAN-1377.
* fix(docs): finish MCP self-description nine-tool wording per Codex review (round 7)
Codex round 7 findings:
[1] catalog_meta.go's padMetaToolDescription still mentioned the
PLAN-969-rollout cmdhelp walker contributing to tools/list. The walker
was retired in TASK-981. Rewrote the tool-surface action description
to match current behavior and explicitly note pad_set_workspace is
registered separately (not enumerated by tool-surface).
[2] actionMetaToolSurface's comment claimed scope includes
pad_set_workspace; the impl only loops env.Catalog. Updated the
comment to be accurate — tool-surface enumerates the eight catalog
tools only, callers should account for pad_set_workspace as a known
extra.
[3] CLAUDE.md and README.md described the MCP surface as if every
listed tool was resource × action. pad_set_workspace takes
'workspace' only. Reworded both to match instructions.md's
'eight resource × action tools plus pad_set_workspace' framing.
Parent: TASK-1387 / PLAN-1377.
|
||
|
|
d1fb61097e |
docs(onboarding): document IDEA-1 trigger phrase across README, CLAUDE.md, and /pad skill (TASK-1138) (#406)
* docs(onboarding): document the IDEA-1 trigger phrase across README, CLAUDE.md, and the /pad skill (TASK-1138) Make the seeded onboarding entry point (PLAN-1131) discoverable in every doc surface a fresh user might land on. README.md Quick Start gains a follow-up paragraph after `pad init`. Names the trigger phrase verbatim so a copy-paste lands deterministically. Tone matches in-product hint copy from PR #403; no "tutorial" / "lesson" language. CLAUDE.md Authentication section gets a paragraph after `pad auth setup` pointing developers + agents at the same trigger phrase. Also enumerates the four seeded refs (IDEA-1 / PLAN-2 / TASK-3 / DOC-4) for context, with pointers to the source-of-truth code (internal/collections/templates_onboarding.go) and design history (PLAN-1131). skills/pad/SKILL.md Adds a bullet under the Onboarding routing section: an explicit "use pad to get IDEA-1" trigger and the schema-aware terminal-status guidance per collection (Ideas → implemented, Plans → completed, Tasks → done, Docs → archived). Frames the seed items as ordinary items the agent reads and acts on — no "onboarding mode" — so the no-marker / no-skill-detection design from PLAN-1131 stays clean. pad-web (../pad-web) is intentionally not touched — separate repo per CONVE-159. Spawned TASK-1142 to pick up the pad-web getting-started flow as a follow-up. Parent: PLAN-1131. Origin: IDEA-1128. * fix(docs): scope the IDEA-1 hint to post-workspace-creation, not bootstrap setup, per Codex review (round 1) Codex caught that the original wording suggested users could go straight to `use pad to get IDEA-1` after `pad auth setup`. But `pad auth setup` only creates the first admin account — no workspace. IDEA-1 is only seeded when a `startup`-template workspace is created (`pad init` or `pad workspace init`). Tightened to call out the precondition explicitly: a startup-template workspace must exist before the trigger phrase resolves. Spawned TASK-1143 to fix the matching CLI hint behavior — PR #403's `printIdeaOneTriggerHint` after `pad auth setup` has the same imprecision and should either drop the IDEA-1 mention or point users at `pad init` first. Out of scope for this docs PR. |
||
|
|
273d75c06e |
docs(mcp): refresh README + SKILL.md for v0.2 surface (TASK-976) (#359)
Updates the in-repo documentation to match what shipped in PLAN-969: - README.md's MCP section now describes the v0.2 catalog (8 tools, resource × action shape) instead of the retired v0.1 verb explosion. Documents both stability constants (CmdhelpVersion 0.1 + ToolSurfaceVersion 0.2) and points consumers at the structured error envelope contract. - skills/pad/SKILL.md gets a one-line callout that the MCP surface is hand-curated and distinct from the CLI verb tree this skill drives. Prevents future "I added a CLI command, why isn't it in MCP?" confusion. - CLAUDE.md was already updated in TASK-981; verified to match. Companion change for getpad.dev/mcp/local lives in ../pad-web. Parent: TASK-976 → PLAN-969. |
||
|
|
4536892923 |
feat(brand): new tagline — Project Management for the agent era (#351)
Retire "Collaborate with your AI agents" in favor of "Project Management for the agent era". Companion change to PerpetualSoftware/pad-web#45 — they ship together so the brand reads consistently across the marketing site and the product. The phrasing leans into the moment without trend-chasing. "agent" carries more weight than "AI" — it points at *how* the technology shows up in your workflow (an autonomous teammate), not just *that* it exists. It's also the unit of change Pad is uniquely structured around (issue IDs, conventions, playbooks — things agents read). This commit only updates plain-text surfaces (README, goreleaser description, embedded PWA manifests, app meta tags). Visual accenting of the word "agent" lives in pad-web (homepage hero <h1> + OG card image), the only places that render the tagline to humans rather than to package managers / OG crawlers. ## Files - README.md — top-of-readme tagline. - .goreleaser.yaml — Homebrew formula description. - web/static/site.webmanifest — embedded PWA description. - web/static/manifest.json — duplicate PWA manifest in the same dir. - web/src/routes/+layout.svelte — <meta name="description"> and <meta property="og:description"> on every app page. ## Verification - make check: 0 errors. golangci-lint, go test ./..., govulncheck, and `cd web && npm run build` all pass. The 6 svelte-check warnings are all pre-existing in files this PR doesn't touch (NestedChildren, ChildItems, roles/+page, console/admin/+page). |
||
|
|
e05ea07d62 |
fix(docs): use canonical wire path capabilities.experimental.padCmdhelp (#342)
Codex caught the same accuracy issue on pad-web that exists in five
spots in this repo: prose described the handshake location as
"serverCapabilities.experimental.padCmdhelp", but per the MCP spec
the InitializeResult shape is
{ result: { capabilities: { experimental: { ... } } } }
There's no `serverCapabilities` field on the wire — `ServerCapabilities`
is the Go-side struct type name in mcp-go; the JSON tag is
`capabilities`. Anyone copying the path out of our docs to navigate
a real JSON-RPC envelope was getting the wrong key.
Updated to `capabilities.experimental.padCmdhelp` (or the fully
qualified `result.capabilities.experimental.padCmdhelp` where the
JSON-RPC envelope context wasn't otherwise obvious) in:
- README.md — public-facing prose
- CLAUDE.md — agent-facing prose
- internal/mcp/version.go — discovery-surfaces doc comment + the
experimentalCapabilityKey doc comment
- internal/mcp/server.go — comment near WithExperimental
- internal/mcp/meta.go — experimentalCapabilities() doc + the wire
shape example (now wrapped under `result` for accuracy)
- internal/mcp/server_test.go — test docstring + failure message
- cmd/pad/mcp.go — comment near RegisterMeta
The Go type `serverCapabilities` in `internal/server/handlers_capabilities.go`
is unrelated (it's the response shape for `GET /api/v1/server/capabilities`)
and stays as-is.
No code/behaviour changes; pure prose accuracy fix. `make check` clean.
Companion fix to pad-web PR #42, which Codex flagged the same issue on.
|
||
|
|
2d98f2a170 |
feat(mcp): advertise cmdhelp_version stability tier in handshake (TASK-963) (#340)
* feat(mcp): advertise cmdhelp_version stability tier in handshake (TASK-963)
External agents (Cursor, Claude Desktop, the future Pad Cloud remote MCP
in PLAN-943) depend on tool names, argument shapes, and resource URIs
being stable across pad releases. Without an explicit contract, any
future surface change breaks consumers silently.
This commit ships the contract on two complementary surfaces:
- serverCapabilities.experimental.padCmdhelp in the initialize handshake
— namespaced map carrying {version, tool_surface_stable}, discoverable
in one round-trip.
- pad://_meta/version static resource — full JSON document with
{pad_version, cmdhelp_version, tool_surface_stable, mcp_protocol_version}
for clients that prefer reading a typed payload.
CmdhelpVersion is pinned at "0.1" — the initial cmdhelp-derived surface
shipped in PLAN-942. Bump the major when tool names / arg shapes /
resource URIs change incompatibly.
Tests:
- TestServer_InitializeHandshake extended to assert the experimental
capability shape on the wire (not just the existence of the field).
- TestBuildMetaPayload_* lock the payload field names + fallback
behaviour.
- TestRegisterMeta_ResourceRoundTrip drives the resource through the
real HandleMessage path so a regression in the dispatcher would
surface as a test failure.
Docs:
- README's MCP section briefly mentions the contract surfaces.
- CLAUDE.md's MCP section gets a stability-contract paragraph + the new
resource URI.
- Public docs at getpad.dev/mcp/local will need a follow-up PR in the
pad-web repo (per CONVE-159) — captured at the end of TASK-963.
Parent: PLAN-942.
* fix(mcp): source MCP protocol version from mcp-go LATEST_PROTOCOL_VERSION per Codex review (round 1)
Codex caught: the local MCPProtocolVersion constant was pinned at
"2024-11-05", but mcp-go@v0.50.0 negotiates "2025-11-25" for clients
that request mcp.LATEST_PROTOCOL_VERSION. The meta resource was
therefore reporting a protocol revision newer than what the server
actually speaks, which defeats the field's purpose for feature
detection (e.g. RFC 8707 Resource Indicators land in 2025-11-25).
Drop the local constant and read mcp.LATEST_PROTOCOL_VERSION at
BuildMetaPayload time so the value tracks whatever revision the
linked library will negotiate. The handshake's serverInfo.version
already does this implicitly via NewMCPServer; making the meta
resource follow the same source-of-truth keeps both surfaces in
lockstep across mcp-go upgrades.
Test updated to assert against mcp.LATEST_PROTOCOL_VERSION instead of
the removed constant, plus an "empty-string" guard in case a future
library refactor unsets the constant.
Parent: PLAN-942.
|
||
|
|
98c4698dcf |
docs(mcp): MCP section in README + CLAUDE.md (TASK-949) (#339)
* docs(mcp): add MCP section to README + CLAUDE.md (TASK-949) Closes PLAN-942's docs task. The pad-web /mcp/local guide (see PerpetualSoftware/pad-web PR #41) is the canonical reference; this commit adds: - README.md "Optional — connect a desktop AI app via MCP" subsection under Getting Started, with the one-line install + link to the full guide. - CLAUDE.md "MCP server" section between "CLI" and "Data Model", documenting the surface (tools / resources / prompts) so agents working in pad's own repo know it exists and where the code lives. No code changes; this PR is documentation-only. Companion to PerpetualSoftware/pad-web PR #41 (the public guide). Parent: PLAN-942. * docs(mcp): clarify MCP tool surface excludes interactive commands (Codex round 1) Codex flagged: README claimed clients can call "every pad command as a tool", but internal/mcp/registry.go's DefaultExcludes list strips ~20 commands (auth setup/login/logout, db ops, init, item edit, project watch, workspace init/import/export/onboard/join, server start/stop, mcp serve/install, completion). The blanket "every" phrasing would mislead users. Reworded to "non-interactive pad commands" with concrete examples of both included (item CRUD, project intelligence, search) and excluded (auth setup, db restore, init, item edit) categories. Full list still lives in CLAUDE.md and the /mcp/local guide. Parent: PLAN-942. * docs(mcp): tighten CLAUDE.md MCP overview to mention the exclude list (Codex round 2) Codex round 2: same overstatement that round 1 caught in README also sat in CLAUDE.md's opening paragraph ("every pad command", "any new pad command lands as an MCP tool for free"). The bullet under the Surface header already qualified it, but the lead sentence framed auto-generation as unconditional. Reworded to "non-interactive pad commands" + "any new pad command that isn't on internal/mcp.DefaultExcludes" so the overview matches the bullet — and the docs match what the code actually does. Parent: PLAN-942. * docs(mcp): replace 'every / for free' framing with explicit review gate (Codex round 3) Codex round 3 still flagged "every leaf pad command" + "any new command lands as an MCP tool for free" — concerned the language implies auto-registration without human review. The behavior IS auto-registration, but the docs now make the human-review step explicit: when adding a pad command, decide whether it belongs on MCP and add to DefaultExcludes if not. Reworded the opening overview AND the bullet: - Lead now says "derived from the cmdhelp Document and filtered against internal/mcp.DefaultExcludes" with the concrete strip list. - New bold sentence: "When adding a new pad command, decide whether it belongs on the MCP surface" + criteria for when to exclude. - Bullet now says "leaf pad commands not in DefaultExcludes (the per-PR review gate above)". Same behavior, more honest framing about what the developer needs to think about. Parent: PLAN-942. |
||
|
|
7cda0d7896 |
feat: rebrand to Perpetual Software + new tagline (IDEA-832) (#273)
Migrates from xarmian/pad to PerpetualSoftware/pad across the entire
repo and updates the product subtitle to "Collaborate with your AI
agents".
Go module rename
- go.mod: github.com/xarmian/pad → github.com/PerpetualSoftware/pad
- All Go imports updated across cmd/pad, internal/{cli,server,store,
models,collections,items,events,metrics,webhooks} (~130 files)
- Test fixtures with the literal repo slug ("xarmian/pad" in JSON
shapes, SSH/HTTPS git URL strings, workspace_context fixtures)
also updated, including the secondary repo entry
(xarmian/pad-web → PerpetualSoftware/pad-web — pad-web was also
moved to the org per branch context)
Docs / config
- README badges, install instructions, brew tap, Docker image, source
build path, sponsor link (sponsor link kept as personal @xarmian)
- Subtitle: "Project management for developers and AI agents." →
"Collaborate with your AI agents." (README, manifests, web layout
meta, .goreleaser homebrew description)
- CONTRIBUTING.md, SECURITY.md, skills/INSTALL.md
- .goreleaser.yaml: homebrew_casks owner, GHCR image, release github
owner, cosign cert-identity regex, comments
- .github/workflows/release.yml: tap/release comments
- deploy/k8s/deployment.yaml: container image
- docs/deployment.md: clone URL
- web/static/{site.webmanifest,manifest.json}: description
- web/src/routes/+layout.svelte: meta description + og:description
Brew tap path is PerpetualSoftware/tap/pad (CamelCase, matches
GitHub user case). GHCR image is ghcr.io/perpetualsoftware/pad
(lowercased per GHCR's URL normalization). CODEOWNERS @xarmian and
FUNDING.yml github: xarmian intentionally retained — those are the
personal maintainer / sponsor account, separate from the org repo.
Verification: go build ./..., go test ./... (all pkgs pass), web
build, and make install all clean (TASK-844, TASK-845).
|
||
|
|
96b3f68b5a |
docs(readme): use pad init as the canonical entry point (#258)
* docs(readme): use pad init as the canonical entry point
The Quick Start and Getting Started sections still walked users
through the deprecated multi-step flow (pad auth configure +
pad workspace init + pad agent install), even though pad init is
a single smart command that orchestrates all six setup steps.
Changes:
- Quick Start: 3 commands -> 2 (brew install + pad init).
- Getting Started: collapsed sections 1-3 ("Configure this client",
"Initialize a workspace", "Install the AI skill") into a single
"Set up Pad" section that uses pad init.
- Template examples updated from pad workspace init --template X
to pad init --template X. --list-templates kept as
pad workspace init --list-templates (the only command that
supports it today).
- Tagline ("No accounts.") + architecture summary ("no accounts.")
-> "No accounts required." Pad supports user accounts with
email/password auth and workspace invitations; the strict claim
contradicted later sections.
- Removed Pad Cloud directive in the Docker section -- Cloud is
not released yet, so the README should not direct users to it.
- Replaced full Docker Compose subsection with a one-line pointer
to docs/deployment.md. Postgres + Redis is an advanced multi-
instance path; the README should keep its binary-first focus.
- Aligned the pad github CLI reference columns (3 lines were
off-spec).
* docs(readme): use pad init in the comparison table too (codex nit)
* docs(readme): reframe Authentication section to point local installs at pad init (codex P2)
* docs(readme): scope pad init bootstrap to local mode (codex P2)
|
||
|
|
29f720c996 |
docs: add real README screenshots (dashboard + board views) (#257)
The README had two TODO placeholders for screenshots that have been
sitting commented-out since the project started. With the launch
imminent, fill them in.
Captures:
- docs/screenshots/dashboard.png — workspace dashboard with Active
Work cards, Active Plans (v0.2 — Collaboration with progress),
collection summaries, recent activity.
- docs/screenshots/board.png — tasks board view, four columns
(Open / In-Progress / Done / Cancelled) with realistic task cards.
- docs/screenshots/list.png — list view (not currently referenced
from the README, but kept as part of the reproducible asset set).
Reproducibility:
web/e2e/screenshots.spec.ts is a gated Playwright spec (skipped
unless PAD_SCREENSHOTS=1) that uses the existing e2e fixture
infrastructure to:
1. Spin up a fresh pad binary against a clean data dir.
2. Bootstrap an admin + workspace seeded with the startup template.
3. Add a realistic demo dataset (1 active plan, 7 tasks across
open/in-progress/done with mixed priorities, 2 ideas).
4. Navigate + capture three views at 1440x900.
To regenerate:
make build
cd web && PAD_SCREENSHOTS=1 PAD_E2E_PORT=17801 \\
npx playwright test screenshots --project=desktop-chromium
Notes:
- Table view (?view=table) was originally in scope but the URL
parser only accepts list/board today; setting via toggle would
require localStorage manipulation. Three screenshots already
cover the README's needs; revisit if/when table view becomes
URL-reachable.
- Dark/light variants were also in scope but the web UI is dark-
mode-only at present, so the captures are dark-only.
Refs: TASK-673
|
||
|
|
89a5647543 |
docs: strip 'Hardening for public deployments' from README (#255)
The OSS package defaults to loopback and is positioned as a local-first, single-user product. A polished operator checklist for self-hosting beyond loopback competes directly with the Pad Cloud funnel — the multi-user team segment we want to convert to hosted. - Strip the entire 'Hardening for public deployments' section from README (network boundary, secrets, authentication, observability, CI gates, quick checklist — five subheadings). - Reword the Docker subsection so single-user-on-LAN / Tailscale / home VPN reads as a positive supported path. Multi-user team setups get a soft handoff to Pad Cloud. - Move the npm audit + govulncheck CI guidance to CONTRIBUTING.md as a Quality Gates subsection — that material is contributor-facing, not user-facing, so it stays. - docs/deployment.md unchanged — multi-user Postgres + K8s recipes still exist there for the determined self-hoster, but unpromoted from the README. No new docs/SELF-HOSTING.md created (initially considered) — would have competed with the hosted-product positioning. Refs: TASK-777 |
||
|
|
157ca4e88f |
chore: bump Go toolchain to 1.26 (TASK-763) (#247)
* chore: bump Go toolchain to 1.26 (TASK-763) Bump Go from 1.25 to 1.26 across all toolchain pins: - go.mod — go 1.25.0 → go 1.26.0 - Dockerfile — golang:1.25-alpine → golang:1.26-alpine - .github/workflows/ci.yml — three setup-go steps (Go, Go-Postgres, E2E jobs) - .github/workflows/release.yml — release pipeline No `toolchain` directive: the repo is pre-launch with no external contributors yet, so we set the floor where we want it (hard requirement). Verified locally before commit: - golangci-lint v2.11.4 builds and runs under Go 1.26.2 (pinned in CI) - golang:1.26-alpine and 1.26.2-alpine images present on Docker Hub - go build ./... clean - go vet ./... clean - go test ./... all pass Parent: PLAN-644 (OSS Repo Hygiene and Launch Polish). * chore: gofmt -w under Go 1.26 (TASK-763) Apply Go 1.26's gofmt to the codebase. ~41 files reformatted, all struct-tag whitespace realignment — no semantic changes. Verified: - gofmt -l ./cmd ./internal returns empty after - go build ./... still clean - go test ./... still passes (run before commit) Bundling the gofmt diff with the toolchain bump in the same PR because the formatting drift is a direct consequence of moving from 1.25 to 1.26; splitting them creates a mandatory two-PR ordering for no value. Parent: PLAN-644. * docs: bump documented Go floor to 1.26 (TASK-763) Match go.mod's hard 1.26.0 requirement in the source-build instructions. Caught by Codex review round 1 on PR #247. - README.md:158 — "Go 1.25+" → "Go 1.26+" - CONTRIBUTING.md:9 — "Go 1.25+" → "Go 1.26+" |
||
|
|
e116b53be5 |
docs: add Go Report Card, GHCR, Sponsors badges to README (TASK-688) (#223)
Grouped README polish to give the repo the public-OSS texture reviewers expect: - Go Report Card — reinforces code-quality signal once the repo is public (goreportcard.com auto-indexes Go repos). - GHCR container image — links directly to the package page; uses a static shields.io badge (GHCR doesn't expose a pulls endpoint the way Docker Hub does, so we avoid the unreliable third-party pull services). - GitHub Sponsors — shows live sponsor count; complements the FUNDING.yml Sponsor button added in TASK-679. CI, Release, and License badges kept as-is. Parent: PLAN-644. |
||
|
|
4f298db4d0 |
docs(readme): add 'Hardening for public deployments' section + govulncheck CI gate (PLAN-643 exit) (#195)
* docs(readme): add 'Hardening for public deployments' + govulncheck CI gate (PLAN-643 exit criteria) Closes the last two exit criteria of PLAN-643 (OSS Security Hardening): - README.md gains a full "Hardening for public deployments" section walking operators through the network boundary (bind addr, TLS, trusted proxies), secrets (PAD_ENCRYPTION_KEY, token scopes, bootstrap window), auth hardening (PAD_IP_CHANGE_ENFORCE, password strength UI messaging, PAD_CORS_ORIGINS), observability (PAD_METRICS_ TOKEN, audit-log shipping), and a deploy-day checklist. Cross- references every relevant env var documented elsewhere. - CI workflow gains a govulncheck step on the Go job, mirroring the existing `npm audit --audit-level=high --omit=dev` gate on the web job. Locally `govulncheck ./...` reports "No vulnerabilities found", so the first run on main should pass. Exit criteria for PLAN-643: [x] All CRITICAL + HIGH + MEDIUM findings closed and verified [x] `npm audit --audit-level=high --production` clean in web/ [x] CSP denies inline event handlers (script-src-attr 'none') [x] Docker default compose publishes to 127.0.0.1 only [x] README has a "Hardening for public deployments" section [x] `govulncheck ./...` clean * fix(ci): pin govulncheck to v1.2.0 instead of @latest (PLAN-643) Addresses Codex P2 on PR #195: tracking @latest on every CI run makes the gate non-deterministic — a future upstream release could change behavior or require a newer Go toolchain than the workflow's pinned `go-version: 1.25` and break unrelated PRs. Pin to the currently- released v1.2.0 (Go 1.26.2 toolchain) and update intentionally. * docs(readme): recommend pinned govulncheck install in hardening section Follows Codex P2 on PR #195: the earlier commit pinned the CI workflow to v1.2.0 but the README's hardening-checklist bullet still told operators to install @latest. Teams copying that into their own CI would re-introduce the non-determinism the pin was meant to fix. Update the docs to recommend a pinned tag (matching the workflow's v1.2.0) and note that the pin should be bumped intentionally. |
||
|
|
5fffee2b9e |
fix(docker): bind to 127.0.0.1 + require POSTGRES_PASSWORD (TASK-661) (#174)
* fix(docker): bind to 127.0.0.1 + require POSTGRES_PASSWORD (TASK-661)
A fresh Docker install previously published 7777 on 0.0.0.0 with a
hardcoded pad:pad Postgres credential. The bootstrap endpoint is
reachable until the first admin is created, so this combination lets
anyone who can route to the host claim the instance — and with M5's
X-Forwarded-For spoof (fixed in TASK-660) chained with the loopback
bootstrap check, it became a full takeover.
Changes:
- docker-compose.yml: publish "127.0.0.1:7777:7777" by default, with a
PAD_BIND_ADDR override for operators who intentionally want LAN
access. Require POSTGRES_PASSWORD via ${VAR:?err} so docker compose
refuses to start when it's unset — can't silently inherit a weak
default credential.
- docker-compose.prod.yml: drop the "change-me-in-production"
placeholder; require the same env var as the base file.
- .env.example: new file documenting POSTGRES_PASSWORD (required),
PAD_BIND_ADDR, REDIS_PASSWORD, PAD_CLOUD_SECRET, PAD_ENCRYPTION_KEY,
PAD_TRUSTED_PROXIES with generation instructions.
- README.md: add a Docker Compose section covering the .env workflow
and the loopback-default → LAN override.
Parent: PLAN-643 (OSS Security Hardening).
* fix(docker): use libpq keyword=value DSN to avoid URI-encoding the Postgres password per Codex P1
Passwords produced by 'openssl rand -base64' often include '/', '+', or ':'
which are reserved in URI userinfo. Injecting them into postgres://user:PASS@...
breaks sql.Open. Switch PAD_DATABASE_URL to the libpq keyword=value form
(host=... password=... dbname=...) where the password is parsed as a single
token regardless of special characters.
Also teach pgDbnameFromURL to parse both DSN shapes so 'pad db backup/restore'
still shows the correct database name in its confirmation prompt.
|
||
|
|
37ee53d21d |
docs: reflect domain-agnostic template library (TASK-618) (#150)
- CLAUDE.md: templates section expanded to list the 6 categories and what ships under each. Calls out the per-template trigger vocabularies (on-commit vs on-candidate-advance vs on-interview-scheduled) so future agents understand the Conventions/Playbooks collections are domain-aware, not software-hardcoded. Points to PLAN-609 + IDEA-583 as the design record. - README.md: Quick Start template examples now include hiring + interviewing, mention the interactive picker when no --template is passed, and frame templates as covering software AND non-software workflows (people, research, content, operations, personal). Parent: PLAN-609. Closes out the last architecture-tranche task. |
||
|
|
bde15d45ca |
Rename Phases to Plans, clean up deprecated aliases (#71)
* Rename "Phases" to "Plans" and clean up deprecated phase aliases
Renames the default "Phases" collection to "Plans" across the full stack:
- DB migration renames existing collections in-place (name, slug, prefix PLAN, icon 🗺️)
- Removes all deprecated Phase* backward-compat aliases from models and store
- Removes --phase CLI flag (use --parent instead)
- Updates convention triggers: on-phase-start/complete → on-plan-start/complete
- Updates dashboard API: active_phases → active_plans, /phases-progress → /plans-progress
- Updates all frontend components, types, and documentation
Closes IDEA-124
* Fix CSRF cookie not being cleared on logout
The SessionAuth middleware was re-issuing a CSRF cookie before the
logout handler could clear it, resulting in two Set-Cookie headers.
Skip CSRF re-issue for /api/v1/auth/ paths since auth endpoints
manage their own CSRF cookies (login sets, logout clears).
* Fix migration issues found in Codex review
- P1: Move doc_type UPDATE from migration 024 into 025, which recreates
the table with the new CHECK constraint first (SQLite enforces CHECK
on UPDATE, so the old constraint would reject 'plan')
- P1: Add PostgreSQL migration 005 for the collection rename (phases →
plans) — previously only existed on the SQLite path
- P2: Recreate FTS triggers, indexes, and rebuild FTS after the table
swap in migration 025 (DROP TABLE drops associated objects in SQLite)
* Fix parent filter field name and sync .agents skill copy
Codex review round 2 findings:
- P1: Parent filter compared against `parent_id` (wrong) instead of
`parent_link_id` — plan filtering in collection view was broken
- P1: .agents/skills/pad/SKILL.md still had old --phase flags and
"Phases" references — synced from the updated .claude copy
- P2: Accept legacy 'phase' filter key for backward compat with
existing saved views that serialized the old key name
* Fix PG migration JSONB casting and add slug collision guards
Codex PR review bot findings:
- P1: PostgreSQL REPLACE/LIKE don't work on JSONB columns — cast
schema::text and fields::text before string ops, then back to ::jsonb
- P1: If a workspace already has a custom 'plans' collection, the
rename hits UNIQUE(workspace_id, slug) — added NOT EXISTS guard
to both SQLite and PostgreSQL migrations
|
||
|
|
89db556e29 | feat(server): add info command for TASK-134 (#52) | ||
|
|
9650c0ec0b |
feat(workspaces): populate context during onboarding for TASK-132 (#50)
* feat(web): add workspace context editor for TASK-131 * feat(workspaces): populate context during onboarding for TASK-132 |
||
|
|
23a7fc2be1 | feat(workspaces): add CLI and API context support for TASK-130 (#46) | ||
|
|
f5649b912e | refactor(cli): group first-release commands for TASK-127 (#45) | ||
|
|
f1e4618013 | feat(cli): add agent query commands for TASK-126 (#44) | ||
|
|
c61f4cdaaa | feat(items): add structured notes for TASK-125 (#43) | ||
|
|
b59f50982f |
feat(auth): add local bootstrap setup for TASK-118 (#37)
* feat(auth): add local bootstrap setup for TASK-118 * fix(auth): honor setup-required bootstrap flow |
||
|
|
123a7aec98 | feat(cli): add client configure flow for TASK-115 (#34) | ||
|
|
eb4e41ad0b | build(embed): stop rewriting embed.go for TASK-112 (#32) | ||
|
|
4dea8ddc83 | docs(docker): default host publishing to localhost for TASK-114 (#31) | ||
|
|
46447e5504 |
feat: user management & authentication (Phase 6) (#14)
* feat: add user management database migration and models
Add migration 012_users.sql with users, sessions, and workspace_members
tables. Add user_id columns to api_tokens, items, comments, activities,
item_links, and item_versions for proper user attribution. Create Go
model structs (User, Session, WorkspaceMember) in models/user.go.
* feat: add store layer for users, sessions, and workspace members
Implement CRUD operations for user management:
- users.go: create, get, update, list, validate password (bcrypt)
- sessions.go: create, validate, delete, cleanup expired (SHA-256 hashed tokens)
- workspace_members.go: add/remove members, role management, access checks
Adds golang.org/x/crypto/bcrypt dependency. Includes 16 new tests
covering all store methods, password validation, session lifecycle,
and workspace membership operations.
* feat: rewrite auth system from single-password to user-based
Replace single-password auth with email/password user authentication:
- New endpoints: POST /auth/register, GET /auth/me
- Rewritten: POST /auth/login (email+password), GET /auth/session
(needs_setup detection), POST /auth/logout (DB session destroy)
- Delete in-memory SessionManager, use DB-backed sessions via store
- New middleware: SessionAuth (cookie→user), RequireAuth (with
fresh-install passthrough when no users exist)
- Remove Password field from config, PAD_PASSWORD env var, SetPassword()
All 23 existing server tests pass (fresh DBs have no users → passthrough).
* feat: add workspace access control middleware
Add RequireWorkspaceAccess middleware that checks workspace_members for
authenticated users, with fallback for legacy API tokens and fresh
installs (no users → implicit owner). Includes role hierarchy helpers
(workspaceRole, requireRole) for downstream permission checks.
Wire middleware into the /{slug} workspace route group.
* feat: add CLI auth commands and credential storage
Add pad login, pad logout, pad whoami commands with credential
storage in ~/.pad/credentials.json (0600 permissions). Update CLI
HTTP client to auto-attach auth tokens and X-Pad-Agent header on
all requests. Add auth API methods (Login, Register, Logout,
CheckSession, GetCurrentUser). Extend .pad.toml with optional
agent_name field. Add golang.org/x/term for masked password input.
* feat: derive actor/source from auth context in all handlers
Replace hardcoded "user"/"web" actor/source strings with auth-aware
helpers. actorFromRequest() derives actor ("user"/"agent" via
X-Pad-Agent header) and source ("web"/"cli" from auth method).
agentMeta() merges agent name into activity metadata. Update all
item, document, comment, and move handlers to use request-based
logActivity/logActivityWithMeta. Remove hardcoded CreatedBy/Source
from all CLI commands — server now determines these from auth context.
* feat: frontend auth — login, registration, auth guard, user menu
Rewrite login page with email/password fields, add registration page
for first-time setup, update auth guard to handle needs_setup redirect.
Add user menu to sidebar with logout. Update API client with new auth
methods (register, login with email, session with needs_setup flag).
* feat: migrate API tokens from workspace-scoped to user-owned
API tokens now have a user_id owner and optional workspace_id scope.
CreateAPIToken takes userID as first parameter. ValidateToken resolves
the token's user into the request context. TokenAuth middleware now
sets ctxCurrentUser when a user-owned API token is used. Add user-
scoped endpoints: GET/POST/DELETE /auth/tokens. Keep workspace-scoped
token endpoints for backwards compatibility.
* feat: workspace membership, invitations, and role enforcement
Add workspace_invitations table (migration 013) with join codes.
Implement invitation store methods (create, get by code, accept,
list). Add member management handlers: list members + invitations,
invite (auto-adds existing users or creates invitation), remove
member, change role, accept invitation by code. Add API routes
under /workspaces/{slug}/members/* and /invitations/{code}/accept.
Add CLI commands: pad members, pad invite, pad join.
* feat: auth tests and documentation updates
Add comprehensive auth endpoint tests: registration flow (first user
becomes admin), login/logout, validation errors, duplicate email,
auth enforcement (401 after users exist, exempt paths), /me endpoint.
Update CLAUDE.md and README.md to document user-based auth system,
replacing old PAD_PASSWORD references with pad login/members/invite
workflow and role-based access control.
* feat: add members management UI to workspace settings page
Add Members section to settings with: member list (avatar, name,
email, role), role change dropdown (owner only), remove button
(owner only), pending invitations display with join codes, and
invite form with email + role picker. Add members API methods to
the TypeScript client (list, invite, remove, updateRole).
* fix: backfill workspace owners for pre-migration workspaces
Add backfillWorkspaceOwners() that runs on server start. For any
workspace with no members, adds the first admin user as owner.
This handles the migration case where workspaces existed before the
user system — without it, the members list shows empty.
* feat: shareable invite links with /join/[code] page
Replace raw join codes with full shareable URLs. Server generates
join_url using its configured base URL (e.g. https://pad.example.com/
join/a3f8b2c1). New /join/[code] page handles the full flow: checks
auth → shows login/register if needed → accepts invitation → redirects
to workspace. Settings page shows "Copy invite link" button that copies
URL to clipboard. CLI outputs shareable link instead of raw code.
* fix: auto-add workspace creator as owner, integrate auth into pad init
handleCreateWorkspace now adds the authenticated user as owner of the
new workspace immediately — no more relying on the startup backfill.
pad init now checks auth status before making API calls. If no users
exist, prompts to register. If not logged in, prompts to login. After
auth, proceeds with workspace creation normally.
* fix: add join_url to invite response type in API client
* fix: address codex review — invite registration, logout token revocation, workspace scoping
- Allow registration with valid invitation_code (fixes invite flow for new users)
- Revoke Bearer session tokens on logout, not just cookies
- Filter workspace listing to user's memberships (admins see all)
|
||
|
|
8f2561529b |
docs: add auth, github integration, and new commands to docs (#8)
- CLAUDE.md: add auth section, auth API endpoints, github/bulk/webhook commands - README.md: add auth section, standup/changelog/deps/github/webhook commands |
||
|
|
4708e5bacf |
docs: Update README, SKILL.md, CLAUDE.md, and add GitHub templates
README: Complete rewrite with value proposition, comparison table, feature showcase, installation guide, architecture diagram, CLI reference. SKILL.md: Add standup, changelog, watch, dependencies, and webhooks to the agent skill so AI tools know about new capabilities. CLAUDE.md: Document webhooks package, new API endpoints, and all new CLI commands. GitHub templates: Bug report and feature request issue templates (YAML), pull request template with checklist. |
||
|
|
a2e5a6622d |
Add Docker support and PAD_DATA_DIR config
- Multi-stage Dockerfile for building from source - Dockerfile.goreleaser for GoReleaser-built release images - GoReleaser config: publish multi-arch Docker images to ghcr.io - Add PAD_DATA_DIR environment variable for configuring data directory - Update README with Docker install option - Add .dockerignore |
||
|
|
d29738bd89 |
Update README for multi-agent support and fix release workflow
- README: update agent integration section to show pad install with all supported tools - README: add pad install step to Quick Start - Release workflow: add web build placeholder before go test to prevent embed failure |
||
|
|
81579847c6 |
Initial release
Pad — project management for developers and AI agents. Single Go binary with embedded SvelteKit web UI, SQLite storage, CLI, and Claude Code /pad skill integration. https://getpad.dev |