# Verify Login Logout

Prove sign-in lands the user where they should be, sign-out really ends the session so...

- Repository: https://github.com/reticlehq/reticle (1299 stars)
- Category: Engineering
- License: Apache-2.0
- Last updated: 2026-11-01
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add reticlehq/reticle --skill verify-login-logout -g -a claude-code -y`
Codex: `npx skills add reticlehq/reticle --skill verify-login-logout -g -a codex -y`
Cursor: `npx skills add reticlehq/reticle --skill verify-login-logout -g -a cursor -y`
Gemini CLI: `npx skills add reticlehq/reticle --skill verify-login-logout -g -a gemini-cli -y`
Claude Code plugin marketplace: `/plugin marketplace add reticlehq/reticle`

## Description

Prove sign-in lands the user where they should be, sign-out really ends the session so a protected page sends them back to sign in, and an expired session asks to sign in again instead of breaking. Use when auth, a login form, a logout button, route guards or token refresh were added or changed, or when a user reports being logged out, or not logged out, unexpectedly.

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# Signed in on screen is not signed in

A login form that shows the dashboard after submit proves the page changed. It does not prove the server accepted the credentials, that signing out ends anything, or that a user whose session ran out gets a sign-in page instead of a blank screen and a loop of 401s.

**Reticle** can check all three in the running app. Not set up? Follow the [`reticle`](https://github.com/reticlehq/reticle/blob/main/skills/reticle/SKILL.md) skill: it installs Reticle, asks the user before `init` changes the app's files, and proves one flow.

## Before you start

- **Use the project's test account.** Take credentials from its seed data, fixtures or `.env.example`, or ask the user. Never type a real person's password.
- **Confirm the session can observe:** `reticle_session({ action: "list" })`. A hidden or throttled tab can accept a click and render nothing. If it is not healthy, report the run as **blocked**, not passed.
- **Step 3 needs a browser Reticle owns.** Forcing an expired session uses `reticle_network_mock`, which works in a leased tab (`reticle_run({ tool: "reticle_lease", args: { action: "acquire", url } })`) or a driven one, and not through the always-on SDK. Without one, do steps 1 and 2 and report step 3 as **unknown**.

## 1. Sign in, and name where it must land

Get the form's refs with `reticle_look({ action: "page", sessionId, mode: "interactive" })`, fill the fields with `reticle_act`, then submit and state the consequence before you click:

```
reticle_act_and_wait({ sessionId, ref: "<sign-in button>", action: "click", until: { kind: "allOf", predicates: [
  { kind: "net", urlContains: "/api/login", ok: true },
  { kind: "route", pathname: "/dashboard" },
  { kind: "element", query: { role: "button", name: "Account" } },
]}})
```

The rest: https://github.com/reticlehq/reticle/blob/HEAD/skills/verify-login-logout/SKILL.md
