Skip to content

docs: agent-facing feature guide - #25

Merged
henrik253 merged 9 commits into
mainfrom
integration
Jul 21, 2026
Merged

docs: agent-facing feature guide#25
henrik253 merged 9 commits into
mainfrom
integration

Conversation

@henrik253

Copy link
Copy Markdown
Owner

Promotes integration to main. Net new content:

  • docs/agent-guide.md — one-page agent guide: mental model, goal → tool map of all
    31 tools, standard workflows (project setup, work session, GPU switch with safe
    endpoint discovery, recovery), env vars, and pitfalls.
  • README "For agents" section — the whole tool surface in ten lines, placed before
    Architecture, linking to the guide. Fixes agents using only a fraction of the features
    after reading the README.

Plan-reviewer ran on the feature commit; all five findings were incorporated before the
feature PR (#23) merged — notably the safe assignment-endpoint discovery flow, the
default-session semantics, and the local-path reopen data-loss pitfall.

Docs-only; 400 tests pass, ruff clean.

🤖 Generated with Claude Code

henrik253 and others added 9 commits July 15, 2026 22:27
docs: require roadmap updates in completing commits
* docs: require roadmap updates in completing commits

* feat: auto-approve Colab MCP connect dialog via managed Chromium

Establishes the Phase 2 browser layer (plan.md §10/§11).

The popup cannot be bypassed: Colab's connect-local-mcp command always awaits
the dialog, it has no remember option, and the only dialog-free entry point is a
private TEST_ONLY.connect() hook that would bypass a consent gate (plan.md §14).
So we click it — only after proving the dialog is ours.

Two gates exist, not one. Beyond Colab's dialog, Chrome blocks a public origin
from reaching localhost (ERR_BLOCKED_BY_LOCAL_NETWORK). Modern Chrome uses the
Local Network Access permission; the older Private Network Access response
headers do not satisfy it. The controller grants local-network-access scoped to
the Colab origin.

Verification uses the dialog's own readonly token field, which Colab prefills
with exactly <token>&<port>: compare against the session, refuse on mismatch,
never leak the token. Success is the server-side connection, not the click.

Mechanism verified by frontend-bundle analysis and a headless end-to-end spike
against the real Colab UI plus a real ColabWebSocketServer; documented in
plan.md §11 so a Colab UI change can be re-verified cheaply.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(demo): unattended MCP approval via managed browser

Wires the auto-approval into the demo so its phases stop needing three
manual popup clicks each (demo README 'one MCP approval per tab').

- SessionManager takes an optional BrowserController; open_connection uses it
  to open and approve the tab, else falls back to webbrowser.open_new. The
  manager already owns one session per notebook_id and the controller owns one
  tab per notebook_id, so no new global or signature churn is needed.
- run_demo.py gains --auto-approve/--headless and a 'login' command that opens
  the managed browser for the operator's one-time Google sign-in. Credentials
  are only ever typed by the operator and live in the gitignored profile.
- Approval failures surface as structured errors, not hangs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(demo): attach to the operator's own Chrome for auto-approval

Google refuses sign-in to automated browsers: even launching the real Chrome
binary, navigator.webdriver stays true and sign-in is blocked, so a
Playwright-launched profile can never hold a usable session. Spoofing that
signal would defeat a security check (plan.md §14), so instead the operator
signs in to a normally-launched Chrome and the demo attaches to it.

- BrowserController gains cdp_url (attach over CDP; never closes a browser it
  does not own) and use_chrome (real Chrome channel, automation flag dropped).
- run_demo.py gains a 'chrome' command that launches Chrome with a debug port
  and its own profile (Chrome refuses remote debugging on the default profile),
  plus --cdp-url for the live phases.
- Sign-in detection now waits for Colab's app shell before judging: a blank page
  trivially lacks the sign-in prompt and used to report success, closing the
  window before the operator could sign in. Regression covered by login_test.py.

Verified live: three notebooks opened and auto-approved with no manual clicks;
each runtime returned {connected: true, accelerator: CPU} from executed code.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(demo): headless operation via exported browser session

A terminal-only server can now run signed in without a display, Chrome, Xvfb
or a desktop. Google only checks for automation at sign-in, so a headless
browser replaying an exported session is already authenticated — verified
live: three notebooks connected headless from the session file alone, each
runtime returning {connected: true, accelerator: CPU} from executed code.

- BrowserController gains session_file (launch headless + storage_state) and
  export_session(), which writes the state 0600 before any bytes reach disk.
  A missing session returns user_action_required naming the fix.
- run_demo.py gains export-session, session-check (exit 0/1, so a scheduler
  alerts instead of hanging) and --session-file.
- CDP_URL now uses 127.0.0.1: Chrome binds the debug port on IPv4 while
  localhost may resolve to ::1 first and refuse the connection.

The session file authenticates as the user with no password or 2FA, so it is
treated as a credential throughout: 0600, gitignored, never logged, and
documented as such. It is not interchangeable with the OAuth client JSON —
that identifies the application, this identifies the user.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat: wire managed-browser auto-approval into the MCP server CLI

The auto-approval flow existed in the library and demo (BrowserController +
SessionManager(browser=...) + server.open_connection) but the shipped entry
point always built SessionManager() bare, so MCP clients still got the manual
popup. New CLI flags close the gap:

- --auto-approve: build + start a BrowserController, pass it to
  SessionManager, close it on shutdown (the manager never owns its lifecycle;
  a nested finally closes it even when a session refuses to close)
- --cdp-url / --headless / --session-file configure the controller; they are
  rejected without --auto-approve, and --cdp-url rejects --headless /
  --session-file (an attached browser is whatever the operator launched)
- behaviour is unchanged when the flags are absent; a start() failure aborts
  before serving, releases what start acquired, and user_action_required
  failures print their remedy instead of a traceback

Roadmap §12 wiring bullet checked off with the cli_test.py::TestAutoApprove
cases (happy paths, invalid flag combinations, failure paths).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Adds the missing setup path from clone to working server: install commands,
MCP-client registration, the two one-time credentials (browser session via an
operator-launched Chrome with CDP attach — the only route Google's sign-in
accepts — and the optional runtime-API OAuth consent), unattended operation via
--auto-approve with an exported session file, and maintenance commands.

Also documents the remote-Linux findings from the 2026-07-20 server run: xrdp/
software-rendered displays need Chrome launched with --disable-gpu, SSH shells
need DISPLAY/XAUTHORITY/DBUS_SESSION_BUS_ADDRESS from the active desktop
session before the keyring or a visible browser is reachable, and a crashed
desktop session can drop the keyring token.

Roadmap: §1 documentation bullet checked; stale wave-status snapshot (still
describing PR #15 as open) refreshed to the post-#19 state.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Agents connected to the server were observed using only a fraction of the tool
surface. Two additions fix discovery:

- docs/agent-guide.md: one-page agent guide — mental model (registered
  notebooks are persistent resources, sessions are replaceable), a goal → tool
  map of all 31 tools, standard workflows (project setup, work session, GPU
  switch with safe endpoint discovery, recovery), env vars, and pitfalls
  (close does not sync, local-path reopen resets to last-synced file, GitHub
  URLs load from the remote branch, endpoints are not mapped to notebooks,
  structured errors).
- README "For agents" section: the whole surface in ten lines, linking to the
  guide, placed before Architecture so an agent reading the README top-down
  knows every feature before any implementation detail.

All tool names, signatures, profile names, and env vars verified against
registry/tools.py, snapshots/tools.py, transfer_tools.py, runtime/tools.py,
server.py, and constants.py; plan-reviewer findings (endpoint discovery flow,
default-session semantics, local-path reopen data loss, snapshot outputs not
re-injected) are incorporated. Out-of-plan docs scope, user-requested;
recorded in the roadmap wave status.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@henrik253
henrik253 merged commit 4838e90 into main Jul 21, 2026
0 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant