← all posts

29 may 2026

I spent today bouncing between a couple of small-but-important reliability fixes: one for my GitHub Pages site (a subtle canvas rendering bug), and another for my OpenCode personal-agent plugin (where packaging/deploy details were causing missing skills and even crashes). A theme emerged: when behavior is “mostly working,” tight verification loops (tests + logs + a reproducible harness) are what keep you from chasing ghosts.

What I learned

  • Canvas state bugs can be “logic-flow” bugs, not math bugs. My dimming/hover-brightness issue came down to an early-return path that skipped applying the default alpha when no mouse movement had occurred.
  • Playwright is useful even for non-UI logic assertions. Sampling pixel/alpha values and taking screenshots gave me a concrete way to prove the regression and confirm the fix, instead of relying on “looks right.”
  • Plugin packaging matters as much as plugin code. In my OpenCode plugin work, multiple failures traced back to distribution details:
  • Skill files being silently skipped due to missing required frontmatter.
  • A plugin showing up “by name” but failing to load because dist/plugin.js wasn’t actually present in the installed artifact.
  • “Works locally” setups breaking due to cache + install-hook assumptions.
  • Guardrails prevent reintroducing deployment drift. If a repo commits built artifacts (like dist/plugin.js), it’s easy for dist/ to drift from src/ unless CI/tests enforce sync.

What I built

  • GitHub Pages fix: Updated the site JS so the canvas dims by default regardless of mouse presence, then brightens on hover. Verified with Playwright and pushed the change.
  • OpenCode personal-agent plugin stabilization:
  • Fixed missing skills/commands by ensuring the skill docs include the expected metadata/frontmatter and adding missing command docs where needed.
  • Reworked the deployment workflow so it’s less fragile (bundling instead of copying half-resolved TypeScript).
  • Added a “dist drift guard” test that rebuilds the bundle and compares it to committed dist/plugin.js, and sanity-checked it by intentionally introducing drift and confirming the test fails.
  • Did repo hygiene: cleaned up stale worktrees/branches after merging PRs.

Experimenting with

  • Hardening install UX for plugins. I explored moving from a “drop a file in a config directory” style install (which tends to show up as a file path and encourages drift) toward a more reproducible git/npm-style install, plus a clearer Quickstart that separates: 1) plugin install
    2) copying “extras” (skills/commands)
    3) environment variables and verification steps (logs + a known slash command like /wrap).