office-hours wireframe render silently fails because browse blocks file:// URLs

Open Beginner friendly
#771 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
72/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
python, shell
Domain
cli, tooling

Research direction

Start in office-hours/SKILL.md.tmpl and reproduce the Visual Sketch flow with the browse binary, noting the blocked file:// navigation. Replace that navigation with the temporary localhost serving pattern described in the issue, then verify that the wireframe is rendered and screenshot, and that the temporary server is cleaned up.

Written by the indexing model from the issue text.

Description

Summary

The office-hours skill generates a wireframe HTML file at /tmp/gstack-sketch-*.html, then tries to render it with:

$B goto "file://$SKETCH_FILE"
$B screenshot /tmp/gstack-sketch.png

This silently fails because the browse binary blocks file:// URLs (added in #17 to prevent SSRF/local resource access). The skill hits the fallback path ("skip the render step") and moves on without telling the user what happened.

Root Cause

validateNavigationUrl() in the browse binary rejects any URL with a file: scheme. This is correct for untrusted external content, but the office-hours skill generates the HTML itself — the file is trusted local content.

The skill's fallback message says:

"Visual sketch requires the browse binary. Run the setup script to enable it."

This is misleading — the browse binary IS set up and working. The issue is the URL scheme, not the binary.

Reproduction

  1. Run /office-hours on any project with a UI component
  2. Let it reach the "Visual Sketch" section where it generates wireframe HTML
  3. Observe: $B goto "file:///tmp/gstack-sketch-*.html" exits with code 1 and the error Blocked: scheme "file:" is not allowed
  4. The skill silently skips the render, screenshot, and "present and iterate" steps

Workaround

Serve the file over HTTP before navigating:

python3 -m http.server 18923 --directory /tmp --bind 127.0.0.1 &
$B goto "http://127.0.0.1:18923/gstack-sketch-1234.html"
$B screenshot /tmp/gstack-sketch.png
kill %1

This works perfectly — the browse binary renders and screenshots the wireframe without issues.

Suggested Fix

In the office-hours skill template (office-hours/SKILL.md.tmpl), replace the direct file:// navigation with a temporary HTTP server pattern:

SKETCH_PORT=$(shuf -i 18000-19000 -n 1)
python3 -m http.server "$SKETCH_PORT" --directory "$(dirname "$SKETCH_FILE")" --bind 127.0.0.1 &
_HTTP_PID=$!
sleep 1
$B goto "http://127.0.0.1:$SKETCH_PORT/$(basename "$SKETCH_FILE")"
$B screenshot /tmp/gstack-sketch.png
kill $_HTTP_PID 2>/dev/null

Alternatively, the browse binary could allowlist file:// URLs that are under /tmp/gstack-* since the skill itself generates them and they're trusted.

Related

  • #17 — original SSRF fix that added file:// blocking
  • #340 — user-facing symptoms of this bug (wireframes never rendered, "present and iterate" step skipped)

Environment

  • macOS (aarch64-darwin)
  • gstack browse binary built and working (verified with http:// URLs)
  • bun, Google Chrome available via Nix
Dominant language
TypeScript
Stars
134k
Forks
19.9k
Avg merge
20h 59m
Merged PRs (30d)
21

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from garrytan/gstack

All issues in garrytan/gstack

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.