Set, lay out and remove a project's wallpaper

RO
19h ago
+1170-19

What

Adds basecamp projects wallpaper so people and agents can set, lay out and remove a project's wallpaper. The limits match the web.

basecamp projects wallpaper set skyline.jpg --mode tile --in "<project>"
basecamp projects wallpaper mode fill --in "<project>"
basecamp projects wallpaper remove --in "<project>"
  • set uploads PNG, JPEG, WebP or AVIF up to 10 MB. The CLI refuses another type, a larger file, or an unknown mode before it sends anything. bc3 sniffs the bytes and refuses a mislabeled file with a 422.
  • mode changes fill or tile through the existing project update, and resends the project's current name.
  • Each command returns the project, with .data.wallpaper set to {url, mode} or absent. projects show adds a Wallpaper: tile line in styled and Markdown output.
  • skills/basecamp/SKILL.md gains a "Project wallpaper" section and an eval case. API-COVERAGE gets a row.

Why

Card: Add ability to add/remove wallpaper. This also covers the wallpaper half of #864.

It depends on two unmerged PRs. https://github.com/basecamp/bc3/pull/14062 adds the endpoint. https://github.com/basecamp/basecamp-sdk/pull/1037 models it. go.mod pins the SDK branch at a pseudo-version. Re-bump after the SDK merges, then re-sync the MCP model and the Nix hash.

Scope

  • Project wallpaper only. Color and logo, the rest of #864 and basecamp-sdk#977, are not covered.
  • remove_project_wallpaper becomes an MCP tool through the model sync. The upload is multipart, so the sync drops it with the other uploads.
  • The bump also brings in basecamp-sdk#1033 and #1032, already on SDK main. Nothing here uses them.

Testing

  • bin/ci passes on this head.

  • End to end, verify-basecamp-cli ran this branch's binary against bc3 #14062 on a local server. Each change was read back from GET /projects/:id.json:

    • set PNG with tile, then JPEG, WebP, and AVIF;
    • mode fill;
    • GIF, HEIC, an 11 MB file and mode stretch, refused locally (exit 1);
    • a text file named .png, refused by the server with a 422 (exit 9);
    • remove, done twice;
    • mode on a project with no wallpaper.

    The wallpaper URL redirects (302). This run found that bc3 accepted the mislabeled text file, which #14062 now fixes.

  • Unit tests cover:

    • every local refusal, with no request sent;
    • the exact multipart field and ?mode=;
    • the mode-only body, {"name":…,"wallpaper_mode":…};
    • the 10 MB boundary;
    • the fallback when the re-read fails.
  • New BATS tests are in e2e/projects.bats. The smoke tests in smoke_projects_write.bats need a live account and mark themselves unverifiable until bc3 ships.


Summary by cubic

Adds basecamp projects wallpaper set|mode|remove so people can set, lay out, and remove a project's wallpaper, matching the web's limits.

  • set accepts PNG, JPEG, WebP, or AVIF up to 10 MB and refuses wrong types, sizes, or modes before sending anything; the server sniffs bytes and rejects mislabeled files.
  • mode changes fill or tile through the existing project update, resending the current name.
  • Each command returns the project, with .data.wallpaper as {url, mode} or absent; projects show prints the mode.
  • remove_project_wallpaper becomes an MCP tool; set is excluded because its multipart body can't cross JSON tool calls.

Dependencies

  • Requires unmerged bc3#14062 (endpoint) and basecamp-sdk#1037 (SDK); go.mod pins the SDK branch.