# Core Concepts This document describes the concepts that are implemented today in PinchTab. ## Server The **server** is the main PinchTab process. Start it with: ```bash pinchtab # or explicitly pinchtab server ``` What the server does: - exposes the main HTTP API and dashboard on port `9867` by default - manages profiles and instances - proxies tab-scoped requests to the correct managed instance - can expose shorthand routes such as `/navigate`, `/snapshot`, and `/action` Important clarification: - the server is the public entry point - for managed instances, the server usually does **not** talk to Chrome directly - instead, it spawns or routes to a per-instance **bridge** process ## Bridge The **bridge** is the single-instance runtime. Start it directly only when you want one standalone browser runtime: ```bash pinchtab bridge ``` What the bridge does: - owns exactly one Chrome browser process - exposes browser and tab endpoints such as `/navigate`, `/snapshot`, `/action`, and `/tabs/{id}/...` - is the process the server launches for each managed instance In normal multi-instance usage, you usually interact with the server, not with bridge processes directly. ## Profiles A **profile** is a Chrome user data directory. It stores persistent browser state such as: - cookies - local storage - cache - browsing history - extensions - saved account state Profile facts that match the current implementation: - profiles are persistent on disk - profiles can exist without any running instance - at most one active managed instance can use a given profile at a time - profile IDs use the format `prof_XXXXXXXX` - `GET /profiles` hides temporary auto-generated profiles unless you pass `?all=true` Create a profile with the API: ```bash curl -X POST http://localhost:9867/profiles \ -H "Content-Type: application/json" \ -d '{ "name": "work", "description": "Main logged-in work profile" }' # Response { "status": "created", "id": "prof_278be873", "name": "work" } ``` ## Instances An **instance** is a managed browser runtime. In practice, one instance means: - one bridge process - one Chrome process - zero or one profile - one dedicated port - many tabs Instance facts that match the current implementation: - instance IDs use the format `inst_XXXXXXXX` - ports are auto-allocated from `9868-9968` by default - instance status is tracked as `starting`, `running`, `stopping`, `stopped`, or `error` - one profile cannot be attached to multiple active managed instances at the same time ### Persistent vs temporary instances There are two common ways to start an instance: 1. with a named profile 2. without a profile ID If you start an instance with a profile ID, the instance uses that persistent profile. If you start an instance without a profile ID, PinchTab creates an auto-generated profile named like `instance-...`. That temporary profile is deleted when the instance stops. So this is the correct mental model: - instances without an explicit profile are **ephemeral** - the implementation still creates a temporary profile directory behind the scenes - that temporary profile is cleanup state, not a reusable long-term profile ### Starting an instance Preferred endpoint: ```bash curl -X POST http://localhost:9867/instances/start \ -H "Content-Type: application/json" \ -d '{ "profileId": "prof_278be873", "mode": "headed" }' # CLI Alternative pinchtab instance start --profileId prof_278be873 --mode headed # Response { "id": "inst_0a89a5bb", "profileId": "prof_278be873", "profileName": "work", "port": "9868", "headless": false, "status": "starting" } ``` ## Tabs A **tab** is a single page inside an instance. Tabs belong to an instance, and therefore inherit that instance's profile state. What a tab gives you: - its own URL and page state - a snapshot of the accessibility tree - action execution such as click, type, fill, hover, and press - text extraction, screenshots, PDF export, cookie access, and evaluation Open a tab in a specific instance: ```bash INST=inst_0a89a5bb curl -X POST http://localhost:9867/instances/$INST/tabs/open \ -H "Content-Type: application/json" \ -d '{"url":"https://pinchtab.com"}' # Response { "tabId": "CDP_TARGET_ID" } ``` Then use tab-scoped endpoints: ```bash TAB=CDP_TARGET_ID curl http://localhost:9867/tabs/$TAB/snapshot curl -X POST http://localhost:9867/tabs/$TAB/action \ -H "Content-Type: application/json" \ -d '{"kind":"click","ref":"e5"}' curl -X POST http://localhost:9867/tabs/$TAB/close ``` ### Are tabs persistent? Usually, no. For managed instances started by the server: - tabs are runtime objects - tabs disappear when the instance stops - profiles persist, but open tabs do not That means the persistent part is the **profile state**, not the tab list. ## Element references Snapshots return element references such as `e0`, `e1`, `e2`, and so on. These refs are useful because they let you interact with elements without writing CSS selectors for common flows. ## Relationships The implementation is easiest to understand with these rules: | Relationship | What is true today | |---|---| | Server -> Instances | One server can manage many instances | | Bridge -> Chrome | One bridge owns one Chrome process | | Instance -> Profile | An instance has zero or one profile | | Profile -> Instance | A profile can have zero or one active managed instance at a time | | Instance -> Tabs | An instance can have many tabs | | Tab -> Instance | Every tab belongs to exactly one instance | | Tab -> Profile | A tab inherits the instance profile, if one exists | Profiles are reusable persistent state. Instances are temporary runtimes that may use a profile. ## Shorthand routes vs explicit routes PinchTab exposes two styles of interaction: ### Explicit routes These always name the resource you want: - `POST /instances/start` - `POST /instances/{id}/tabs/open` - `GET /tabs/{id}/snapshot` - `POST /tabs/{id}/action` This is the clearest model for multi-instance work. ### Shorthand routes These omit the instance and sometimes the tab: - `POST /navigate` - `GET /snapshot` - `POST /action` - `GET /text` These route to the "current" or first running instance. ## Recommended mental model For most users, this is the right sequence: 1. start the server with `pinchtab` 2. create a profile if you need persistence 3. start an instance from that profile 4. open one or more tabs in that instance 5. snapshot a tab 6. act on refs from that snapshot If you do not need persistence: 1. start an instance without `profileId` 2. use it normally 3. stop it when done 4. let PinchTab delete the temporary profile automatically ## Example workflows ### Workflow 1: persistent logged-in browser ```bash PROFILE_ID=$(curl -s -X POST http://localhost:9867/profiles \ -H "Content-Type: application/json" \ -d '{"name":"work"}' | jq -r '.id') INST=$(curl -s -X POST http://localhost:9867/instances/start \ -H "Content-Type: application/json" \ -d "{\"profileId\":\"$PROFILE_ID\",\"mode\":\"headed\"}" | jq -r '.id') TAB=$(curl -s -X POST http://localhost:9867/instances/$INST/tabs/open \ -H "Content-Type: application/json" \ -d '{"url":"https://pinchtab.com/login"}' | jq -r '.tabId') curl http://localhost:9867/tabs/$TAB/snapshot ``` Use this when you want cookies and account state to survive instance restarts. ### Workflow 2: disposable run ```bash INST=$(curl -s -X POST http://localhost:9867/instances/start \ -H "Content-Type: application/json" \ -d '{"mode":"headless"}' | jq -r '.id') TAB=$(curl -s -X POST http://localhost:9867/instances/$INST/tabs/open \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com"}' | jq -r '.tabId') curl http://localhost:9867/tabs/$TAB/text curl -X POST http://localhost:9867/instances/$INST/stop ``` Use this when you want a clean, throwaway session. ## Summary The durable object in PinchTab is the **profile**. The runtime object is the **instance**. The page object is the **tab**. The **server** manages them, and the **bridge** executes them.