Skip to content

Set, lay out and remove a project's wallpaper - #948

Open
robzolkos wants to merge 4 commits into
mainfrom
project-wallpaper
Open

robzolkos wants to merge 4 commits into
mainfrom
project-wallpaper

Conversation

@robzolkos

@robzolkos robzolkos commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

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. basecamp/basecamp-sdk#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 Project wallpaper and color can't be read or set through the API or CLI #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.

Written for commit 53a29b6. Summary will update on new commits.

View guided diff Turn on auto-fix

Pin the SDK at 4e1cf312 (scripts/bump-sdk.sh), which adds
Projects().UpdateWallpaper and RemoveWallpaper, a wallpaper {url, mode}
on Project, and wallpaper_mode on UpdateProjectRequest. The bump also
brings in the SDK's other changes since d69e9669: who completed a to-do,
card or subtask (basecamp-sdk#1033) and a Rust-only due-date fix
(basecamp-sdk#1032).

Re-vendor the MCP model from that commit (scripts/sync-mcp-model.sh).
UpdateProjectWallpaper is a multipart upload, which the JSON tool-call
convention cannot carry, so the sync drops it with the other uploads;
remove_project_wallpaper is served. Update the Nix vendorHash, verified
by a Docker Nix build.
basecamp projects wallpaper set <file> [--mode fill|tile]
basecamp projects wallpaper mode <fill|tile>
basecamp projects wallpaper remove

The project comes from --project/--in, then the configured default, as
for other project-scoped commands; the positional slot is the file or
the mode. Before anything is sent, set refuses a file that is not PNG,
JPEG, WebP or AVIF or is over 10 MB, and both set and mode refuse a mode
other than fill or tile. The formats and the cap are named once and feed
the help and the refusals. The server sniffs the bytes and holds the
web's rules (editors only, agents refused), and its 422 or 403 comes
back as the error.

mode goes through PUT /projects/:id.json with wallpaper_mode, sending the
current name the SDK requires and nothing else. Each command answers
with the project re-read, so the output shows wallpaper {url, mode}, or
no wallpaper after remove; a failed re-read falls back with a notice,
since the change has already happened.
The skill says which commands change a wallpaper and what an agent
cannot learn from leaf help in time: an agent profile is always refused,
so retrying or reaching for basecamp api is wrong. An eval case holds
that the agent uses wallpaper set rather than projects update.

API-COVERAGE gains a BC5 projects (wallpaper) row for the two new
endpoints, and the totals move from 209 to 211.
Styled and Markdown project output listed no wallpaper, so a person
running projects show or a wallpaper command saw nothing of it. Show
the mode under Info when one is attached. The URL is a signed-in
redirect, no use to read in a terminal, so it stays in JSON only.
@robzolkos
robzolkos requested a review from a team as a code owner October 23, 2026 01:06
Copilot AI balanced review requested due to automatic review settings October 23, 2026 01:06
@github-actions github-actions Bot added commands CLI command implementations sdk SDK wrapper and provenance tests Tests (unit and e2e) skills Agent skills output Output formatting and presentation docs deps labels Oct 23, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the organization has exhausted its available GitHub AI Credits or reached a budget that stops additional usage. An organization owner can increase the applicable AI Credits budget or wait for the usage allowance to reset. Learn about budgets for usage-based billing. Review the organization's AI Credits budgets.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commands CLI command implementations deps docs output Output formatting and presentation sdk SDK wrapper and provenance skills Agent skills tests Tests (unit and e2e)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants