You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
app: showing a local image registers its folder as a project #58762
When the web app shows a local image given by absolute path (a read preview, or an image in markdown, which uses the same loader), it fetches it with the image's parent folder as the location (readLocalImage in packages/app/src/runtime/server/image.ts: "Scope absolute images to their parent, including files outside the project"). Naming a location makes the server resolve and persist it. So if that folder isn't inside a known project, it becomes a new project at the top of the project list, and its location services boot: config, plugins, file watchers, and a connection to every configured MCP server, all for that folder.
Opening one preview of a render outside any repository (/mnt/d/Projects/vrchat/tripo/bounty/eval/views.png) did exactly that: a new project for …/bounty/eval/, and the log shows location services booted for it followed by three mcp connected lines. Two other image folders had become projects earlier the same day, booted with the same trailing-slash location readLocalImage produces. The projects stay: there is no API to archive or delete one, and the hourly sweep only archives projects whose directory is gone.
Possible fixes: resolve the preview's location without persisting it (Project.resolve takes persist: false since 2.1.4), or read images inside the session's directory with the session's location, as relative paths already are.
Thanks for the detailed report. I can confirm this on 2.1.4, and it still happens on the latest dev (2dc8db4).
The script below runs opencode serve with a stub MCP server and sends the request readLocalImage makes for an absolute image path: GET /api/fs/read/views.png?location[directory]=<image folder>/. The image comes back fine, but then:
GET /api/project lists the image folder as a new project;
the server log shows location services booted for that folder (with the trailing slash), plus a file watcher on it;
the MCP server starts a second time, with the image folder as its working directory.
The server-side location resolution saves any directory it's given as a project. A maintainer will take a look.
Reproduction script (repro.sh)
#!/usr/bin/env bash# Reproduces anomalyco/opencode#58762 against the server API, sending exactly the# request the web app's readLocalImage makes for an absolute image path.# Usage: ./repro.sh -> uses `opencode` from PATH# OC_DEV=/path/to/repo ./repro.sh -> runs the CLI from a source checkoutset -u
ROOT=$(mktemp -d /tmp/opencode/r58762.XXXX)export HOME=$ROOT/home XDG_CONFIG_HOME=$ROOT/home/.config XDG_DATA_HOME=$ROOT/home/.local/share XDG_STATE_HOME=$ROOT/home/.local/state XDG_CACHE_HOME=$ROOT/home/.cache
mkdir -p "$XDG_CONFIG_HOME/opencode""$ROOT/project""$ROOT/outside/eval"# A fake stdio MCP server that just records each launch (with its cwd) and stays alive.
cat >"$ROOT/fake-mcp.sh"<<MCP#!/usr/bin/env bashecho "launched cwd=\$PWD" >> "$ROOT/mcp-launches.log"exec sleep 600MCP
chmod +x "$ROOT/fake-mcp.sh"
cat >"$XDG_CONFIG_HOME/opencode/opencode.json"<<CFG{ "mcp": { "fake": { "type": "local", "command": ["$ROOT/fake-mcp.sh"] } } }CFG
(cd "$ROOT/project"&& git init -q && git -c user.email=a@b -c user.name=a commit -q --allow-empty -m init)
# 1x1 PNG outside any projectprintf'\x89PNG\r\n\x1a\n\0\0\0\rIHDR\0\0\0\x01\0\0\0\x01\x08\x06\0\0\0\x1f\x15\xc4\x89\0\0\0\rIDATx\x9cc\xf8\x0f\0\0\x01\x01\0\x05\x18\xd8N\0\0\0\0IEND\xaeB`\x82'>"$ROOT/outside/eval/views.png"if [ -n"${OC_DEV:-}" ];then
OC=(bun --conditions=browser --preload="$OC_DEV/packages/tui/node_modules/@opentui/solid/scripts/preload.js""$OC_DEV/packages/cli/src/index.ts")
else
OC=(opencode)
fi
PORT=4599
export OPENCODE_PASSWORD=repro
curl() { command curl -u opencode:repro "$@"; }
(cd "$ROOT/project"&&"${OC[@]}" serve --hostname 127.0.0.1 --port $PORT --print-logs --log-level info >"$ROOT/server.log"2>&1&)
foriin$(seq 1 60);do curl -sf "http://127.0.0.1:$PORT/api/project">/dev/null 2>&1&&break; sleep 1;done
API="http://127.0.0.1:$PORT"echo"== projects before"
curl -s "$API/api/project";echoecho"== open the session's project (as the app does)"
curl -s -o /dev/null -w "%{http_code}\n" -G "$API/api/location" --data-urlencode "location[directory]=$ROOT/project"
sleep 2
echo"== projects after opening the project"
curl -s "$API/api/project";echoecho"== readLocalImage request: GET /api/fs/read/views.png?location[directory]=<image parent>/"
curl -s -o /dev/null -w "%{http_code} %{content_type} %{size_download} bytes\n" -G "$API/api/fs/read/views.png" --data-urlencode "location[directory]=$ROOT/outside/eval/"
sleep 3
echo"== projects after showing the image"
curl -s "$API/api/project";echoecho"== fake MCP launches"
cat "$ROOT/mcp-launches.log"2>/dev/null
echo"== server log lines mentioning the image folder"
grep -n "outside/eval\|location services booted\|mcp""$ROOT/server.log"| cut -c1-300 | tail -20
pkill -f "serve --hostname 127.0.0.1 --port $PORT"||true
Related: #58795. These stray image-folder locations never stay evicted while a web page is open, because the page's MCP refresh at eviction boots them again. So each one keeps its MCP servers and watchers loaded indefinitely, not just for an hour.
Activity
opencode-agent commentedon Oct 24, 2026
Thanks for the detailed report. I can confirm this on 2.1.4, and it still happens on the latest
dev(2dc8db4).The script below runs
opencode servewith a stub MCP server and sends the requestreadLocalImagemakes for an absolute image path:GET /api/fs/read/views.png?location[directory]=<image folder>/. The image comes back fine, but then:GET /api/projectlists the image folder as a new project;location services bootedfor that folder (with the trailing slash), plus a file watcher on it;The server-side location resolution saves any directory it's given as a project. A maintainer will take a look.
Reproduction script (repro.sh)
Run it:
bash repro.shlsequeiraa commentedon Oct 24, 2026
Related: #58795. These stray image-folder locations never stay evicted while a web page is open, because the page's MCP refresh at eviction boots them again. So each one keeps its MCP servers and watchers loaded indefinitely, not just for an hour.