Skip to content

feat(web): keep the selected conversation in the address bar - #78

Merged
adityak74 merged 1 commit into
mainfrom
feat/session-in-url
Aug 21, 2026
Merged

feat(web): keep the selected conversation in the address bar#78
adityak74 merged 1 commit into
mainfrom
feat/session-in-url

Conversation

@adityak74

Copy link
Copy Markdown
Contributor

Selecting a conversation changed the page and not the URL, so a reload went back to a new chat and the conversation you were reading was two clicks away again. Nothing you would reasonably bookmark, send to yourself, or reach with the back button was reachable.

The id now rides in a query parameter, and the page opens whatever the URL names on load and on back/forward.

Why a query parameter and not a path

A path would need the server to serve index.html for /s/<id>. A reload on a path the server does not know is exactly the bug being fixed — the fix would have depended on fixing it twice. A query parameter rides along on the existing static route and needs no server change at all.

The URL is now an input

Every other session id in the page comes from the server. This one comes from whatever is in the address bar, so it gets its own module and is parsed and refused rather than trusted.

api.ts already encodes the value into the request path, so this is not the only thing between a hostile URL and a bad request — but a value that cannot be a real id should not produce a request at all:

?session=../../etc/passwd   → null → new chat
?session=<script>           → null → new chat
?session=a b                → null → new chat
?session=<129 chars>        → null → new chat

Refusing means opening a new chat, not showing an error.

Three smaller decisions

  • Other query parameters survive a selection. token is how a non-loopback server is reached at all; dropping it on a click would log the page out.
  • Restoring from the URL does not push a history entry. Coming back to what the URL already says is not a navigation, and an extra entry would make the back button walk through duplicates.
  • A link to a deleted conversation falls through to a new chat. Clicking a stale link is a normal thing to do, not a fault to report — so the restore runs after the session list is read, and a missing id is simply not found.

Verification

11 unit tests on the parsing and building, which is where the logic is. Watched them fail before the module existed.

Also verified in a real browser: select a conversation → URL becomes ?session=18cdeff3d7c38b78-9dc2 → reload → transcript, sidebar highlight, and title all come back.

npm run check clean, npm test green (149 tests, up from 138), npm run build clean.

Pre-existing, not from this change: opening a session logs a 404 on /api/sessions/:id/auto-approve. openSession already called refreshApprovalMode() before this PR, so the change only makes it visible on load too. Worth a separate look.

https://claude.ai/code/session_01KGPVQ8wUG7h36zashWYCp4

Selecting a conversation changed the page and not the URL, so a reload
went back to a new chat and the conversation you were reading was two
clicks away again. Nothing you would reasonably bookmark, send to
yourself, or reach with the back button was reachable.

The id now rides in a query parameter, and the page opens whatever the
URL names on load and on back/forward.

A query parameter rather than a path segment on purpose. A path would
need the server to serve index.html for /s/<id>, and a reload on a path
the server does not know is exactly the bug being fixed, so the fix
would have depended on fixing it twice. A query parameter rides along on
the existing static route and needs no server change at all.

Its own module because adding this makes the URL an input. Every other
session id in the page comes from the server; this one comes from
whatever is in the address bar, so it is parsed and refused rather than
trusted. api.ts already encodes the value into the request path, so this
is not the only thing between a hostile URL and a bad request, but a
value that cannot be a real id should not produce a request at all.
Traversal, spaces, angle brackets and anything over 128 characters are
refused, and refusing means opening a new chat rather than showing an
error.

Three smaller decisions worth stating. Other query parameters survive a
selection: token is how a non-loopback server is reached at all, and
dropping it on a click would log the page out. Restoring from the URL
does not push a history entry, since coming back to what the URL already
says is not a navigation. And a link to a conversation that no longer
exists falls through to a new chat, because clicking a stale link is a
normal thing to do and not a fault to report.

Eleven tests on the parsing and building, which is where the logic is.
Verified in a browser as well: select, reload, and the transcript,
sidebar highlight and title all come back.

Claude-Session: https://claude.ai/code/session_01KGPVQ8wUG7h36zashWYCp4
@adityak74
adityak74 merged commit 5eae555 into main Aug 21, 2026
7 checks passed
@adityak74
adityak74 deleted the feat/session-in-url branch August 21, 2026 22:05
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