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.