|
|
@@ -0,0 +1,128 @@
|
|
|
|
|
|
|
|
# Handoff: workbench-server — path traversal fixed, page write-back added, MCP registered
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Session Metadata
|
|
|
|
|
|
|
|
- Created: 2026-09-28 16:34:42
|
|
|
|
|
|
|
|
- Project: /home/claude/bin/workbench-server
|
|
|
|
|
|
|
|
- Branch: master (pushed to git.sethpc.xyz/Seth/workbench-server)
|
|
|
|
|
|
|
|
- Session duration: ~1.5 h (shared with IO-102 work)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Recent Commits (for context)
|
|
|
|
|
|
|
|
- a6766e8 docs: document page write-back via POST /log
|
|
|
|
|
|
|
|
- 05fcb7f feat: POST /log from the page + load state.json on page open
|
|
|
|
|
|
|
|
- 6562250 fix: block path traversal in static handler
|
|
|
|
|
|
|
|
- 4b55135 docs: add open source subheading
|
|
|
|
|
|
|
|
- c97adfc docs: README and INSTALL.md — AI-guided setup with SSH ControlMaster
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Handoff Chain
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- **Continues from**: None (first handoff; earlier history lives in `~/bin/claude_analog/SESSION.md`, "Workbench MCP Server" section)
|
|
|
|
|
|
|
|
- **Supersedes**: None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Current State Summary
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The workbench MCP server was already built but had never been used live. This session gave it a debug run: tests passed and scaffold/HTTP/WS/log/stop worked, but the MCP never loaded because it was only listed under `mcpServers` in `~/.claude/settings.json`, which Claude Code ignores. It is now registered at user scope (`claude mcp add --scope user workbench -- /home/claude/.local/bin/workbench mcp`) and shows ✔ Connected. Along the way I found and fixed a LAN-exposed path traversal (any file readable by `claude` was servable). I also added `POST /log` so pages can record data, and made the scaffold load `state.json` when a page opens. 18/18 tests pass. First real project: `~/workbench/io102` (see `~/bin/claude_analog/.claude/handoffs/`).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Codebase Understanding
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Architecture Overview
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- `src/workbench/server.py`: `WorkbenchServer` (testable core) + `create_mcp_server` (FastMCP wrapper, 6 tools). Each project gets its own aiohttp app on a port from 8070 up: `/ws`, `POST /log`, static files under the project dir.
|
|
|
|
|
|
|
|
- `src/workbench/project.py`: on-disk layout under `~/workbench/<name>/`: `index.html` (from scaffold), `state.json`, `session.md`/`.jsonl`, `cost-log.jsonl`, `.server.json` (pid/port).
|
|
|
|
|
|
|
|
- `src/workbench/scaffold.html`: WS client. State keys are `template` (HTML), `styles`, `script` (run via `new Function`). On load: fetch `state.json`, fall back to localStorage.
|
|
|
|
|
|
|
|
- Editable pip install (`~/.local/bin/workbench` → this source tree), so source edits apply on the next MCP start.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Critical Files
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| File | Purpose | Relevance |
|
|
|
|
|
|
|
|
|------|---------|-----------|
|
|
|
|
|
|
|
|
| `src/workbench/server.py` | HTTP/WS/MCP | Static handler now resolves paths and requires `is_relative_to(root)` |
|
|
|
|
|
|
|
|
| `src/workbench/scaffold.html` | Browser client | Log feed renders as text (browsers can now POST entries) |
|
|
|
|
|
|
|
|
| `tests/test_server.py` | Includes live-server tests for traversal and POST /log | |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Key Patterns Discovered
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- Tests use a `tmp_workbench` fixture; live-server tests call `server._start_http_server` directly and use aiohttp's ClientSession.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Work Completed
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Tasks Finished
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [x] Debug run: pytest, a live smoke test, and an MCP stdio handshake (all 6 tools listed)
|
|
|
|
|
|
|
|
- [x] Registered the MCP at user scope (`~/.claude.json` backed up to `~/.claude/.backup-claude.json.*` / `~/.claude/.backup/`)
|
|
|
|
|
|
|
|
- [x] Fixed path traversal (commit 6562250), with a test
|
|
|
|
|
|
|
|
- [x] Added POST /log + load-from-state.json + text-only log feed (05fcb7f), with a test
|
|
|
|
|
|
|
|
- [x] README note (a6766e8)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Files Modified
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| File | Changes | Rationale |
|
|
|
|
|
|
|
|
|------|---------|-----------|
|
|
|
|
|
|
|
|
| `src/workbench/server.py` | traversal guard; `log_handler` | security; page write-back |
|
|
|
|
|
|
|
|
| `src/workbench/scaffold.html` | fetch state.json on load; text-only log entries | new devices see content; no script injection via /log |
|
|
|
|
|
|
|
|
| `tests/test_server.py` | 2 tests | |
|
|
|
|
|
|
|
|
| `README.md` | write-back paragraph | |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Backups: `src/workbench/.backup/`, `tests/.backup/`, `.backup/README.md.*`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Decisions Made
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Decision | Options Considered | Rationale |
|
|
|
|
|
|
|
|
|----------|-------------------|-----------|
|
|
|
|
|
|
|
|
| Browser write-back via `POST /log` reusing `append_log` | A separate readings store | One log for humans and the AI; `workbench_read_log` already covers resume |
|
|
|
|
|
|
|
|
| Server for io102 was run as a session-scoped background task, not detached | nohup/setsid daemon | A detached server would block live pushes from a later MCP session (see gotcha) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Pending Work
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Immediate Next Steps
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1. Nothing blocking. Next real use is the IO-102 readings session (driven from `~/bin/claude_analog`).
|
|
|
|
|
|
|
|
2. Optional: fix reattach so live pushes work across processes (see gotcha). Simplest option: when `workbench_scaffold` finds a live server owned by another pid, have `workbench_state` POST the state to that server (e.g. a new `POST /state` endpoint) instead of broadcasting to an empty local client set.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Blockers/Open Questions
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] `rival-llms` MCP is also only in `settings.json`'s `mcpServers`, so it doesn't load either. Not touched; ask Seth whether he wants it.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Deferred Items
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- The FastMCP `serverInfo` version reports 1.26.0 (the SDK's version), not 0.2.0. Cosmetic.
|
|
|
|
|
|
|
|
- `workbench serve <name>` passes the name as the title, which overwrites index.html's title. Cosmetic.
|
|
|
|
|
|
|
|
- No favicon (a 404 in the browser console). Cosmetic.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Context for Resuming Agent
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Important Context
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- The README claim "reattach… browser stays connected" is only half true. The reattaching process has an empty ws_clients set, so `workbench_state` writes state.json but browsers see it only after a refresh.
|
|
|
|
|
|
|
|
- `POST /log` has no auth. It's LAN-only, like the rest of the server. Anyone on the LAN can append log lines, but can't read files outside the project or inject script into the feed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Assumptions Made
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- LAN trust model (no auth) is acceptable for Seth's homelab.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Potential Gotchas
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- Playwright's bundled browsers are not installed; use `chromium.launch(executable_path="/usr/bin/chromium")`.
|
|
|
|
|
|
|
|
- MCP tools only appear in Claude Code sessions started after registration.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Environment State
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Tools/Services Used
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- `workbench` MCP (user scope), `gitea push`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Active Processes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- None persistent. The io102 server from 2026-09-28 was session-scoped.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Environment Variables
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Related Resources
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- `~/bin/claude_analog/.claude/handoffs/2026-09-28-163442-io102-focus-ready-for-readings.md`
|
|
|
|
|
|
|
|
- `docs/superpowers/plans/2026-03-30-workbench-v2.md`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Security Reminder**: Before finalizing, run `validate_handoff.py` to check for accidental secret exposure.
|