# Anti-Patterns

| Bad | Why bad | Good |
| --- | --- | --- |
| Missing `OMNIBOT_SESSION_TOKEN` | Workflows can share implicit state across agents. | `OMNIBOT_SESSION_TOKEN=research omnibot snapshot -i --tab-id <TAB_ID>` |
| Missing `--tab-id` | The command may target the wrong page. | Pass `--tab-id <TAB_ID>` on every page-state command. |
| `execute-js` first | JavaScript bypasses standard browser interaction and hides better evidence. | Try semantic find, snapshot refs, selectors, DOM, and mouse first. For CSS-only dropdowns, use JavaScript only after the trigger clicked, options remain absent from `snapshot -i`, and higher tiers cannot complete open-then-select. |
| Reusing `@eN` across tabs | Refs are tab-scoped and may point to a different element elsewhere. | Take a fresh `snapshot -i --tab-id <TAB_ID>` per tab. |
| Relying on implicit tab targeting | It is unavailable and unsafe for concurrent workflows. | Use explicit `--tab-id` on every page-state command. |
| Using sleep instead of wait | Fixed sleeps are flaky and either too short or too slow. | Use `omnibot wait --text`, `--url`, selector state, load state, or `--fn`. |
| Acting without verify | Command success is not task success. | Run `snapshot`, `get`, `is`, or `wait` after every action. |
| Claiming success without evidence | The browser may not have changed as expected. | Cite verified URL, text, element state, screenshot, console, or network evidence. |
| Raw CSS before semantic find | CSS is more brittle and less tied to user intent. | Start with `find role/text/label/placeholder/testid`. |
| Screenshot when text extraction is enough | Screenshots cost more and are harder to parse. | Use `read` for page content or `get text` for a selector. |
| Using `read` before an action workflow | `read` returns text, not stable action targets. | Use `find`, `snapshot -i`, `get`, or `is` for click/fill/verify workflows. |
| Headless expecting existing user login | Headless does not automatically share the user's visible browser session. | Use visible/background mode for existing login or explicitly log in headless. |
| Mixing multiple workflows in one session token | Agents can overwrite each other's default state. | Use different tokens: `research`, `checkout`, `debug`. |
| Using default tab state in concurrent agents | There is no default tab. Every page command requires explicit `--tab-id`. | Discover or create a tab, save its id, and pass `--tab-id`. |
| Not checking doctor/tabs before troubleshooting | You may debug page logic when the runtime is disconnected. | Run `omnibot doctor` and `omnibot tabs` first. |
| Using `tabs[0]` or the first tab | The first tab is often a user tab or the transport tab, not the workflow target. | Create or identify the intended tab and store its full id. |
| Treating transport as target | Extension routing may use a different tab than the page being acted on. | Always pass `--tab-id <TAB_ID>` and verify with `get url --tab-id <TAB_ID>`. |
| Closing discovered user tabs | Cleanup can destroy the user's real work. | Track only tool-created tabs and close only those ids. |
| Leaving worker-token tabs untracked | Cross-token test tabs can remain open or auto-close later. | Add every worker-created tab id to cleanup tracking. |

## Red Flags

- "I can just use the current tab."
- "This is only one click, no need to verify."
- "JavaScript is faster."
- "The ref probably still points to the same element."
- "A screenshot is enough even though I need text."
- "Sleep should be fine."
- "The trigger clicked, so another `find text` should eventually select the option."
- "`snapshot -i` cannot see the option, so the element must not exist."
- "This dropdown is custom, so I can start with JavaScript."

All of these mean: stop, re-enter the standard pattern, and make state explicit.
