File size: 8,147 Bytes
6a7089a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | # 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.
|