File size: 4,665 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
# Orchestration

This page describes the current orchestration layer in PinchTab: how the server launches, tracks, routes to, and stops browser instances.

## Scope

The orchestrator is part of server mode. It is responsible for:

- launching managed instances as child `pinchtab bridge` processes
- attaching externally managed Chrome instances when attach policy allows it
- tracking instance status and metadata
- routing tab-scoped requests to the owning managed instance
- stopping managed instances and cleaning up registry state

It does not execute browser actions directly. That work happens inside the bridge runtime.

## Current Runtime Shape

```mermaid
flowchart TD
    S["PinchTab Server"] --> O["Orchestrator"]

    O --> M1["Managed Instance"]
    O --> M2["Managed Instance"]
    O -.->|attach| A1["Attached External Instance"]

    M1 --> B1["pinchtab bridge child"]
    M2 --> B2["pinchtab bridge child"]

    B1 --> C1["Chrome"]
    B2 --> C2["Chrome"]
```

## Launch Flow

For a managed instance, the orchestration flow is:

```mermaid
flowchart LR
    R["Start Request"] --> V["Validate profile + port"]
    V --> W["Write child config"]
    W --> P["Spawn pinchtab bridge"]
    P --> H["Poll /health on loopback addresses"]
    H --> S{"Healthy before timeout?"}
    S -->|Yes| OK["Mark running"]
    S -->|No| ER["Mark error"]
```

What the code does today:

- validates the profile name before launch
- allocates a port when one is not supplied
- prevents more than one active managed instance per profile
- prevents reusing a port already in use
- writes a child config file under the profile state directory
- launches `pinchtab bridge`
- polls `/health` on `127.0.0.1`, `::1`, and `localhost`
- moves the instance from `starting` to `running` or `error`

## Attach Flow

Attach is a separate path for an already running browser.

```mermaid
flowchart LR
    R["POST /instances/attach"] --> P["Validate attach policy"]
    P --> A["Register external instance"]
    A --> L["Add to instance registry"]
```

Current attach behavior:

- requires `security.attach.enabled`
- validates the CDP URL against `security.attach.allowSchemes`
- validates the host against `security.attach.allowHosts`
- registers the instance as `attached: true`
- does not start or stop an external Chrome process

## Routing Model

The orchestrator is also the routing layer for multi-instance server mode.

```mermaid
flowchart LR
    R["Tab-scoped request"] --> T["Resolve tab owner"]
    T --> C["Locator cache"]
    C -->|hit| P["Proxy to instance port"]
    C -->|miss| F["Fetch /tabs from running instances"]
    F --> P
```

Today, tab routing works like this:

- for routes such as `/tabs/{id}/navigate` and `/tabs/{id}/action`, the server resolves which instance owns the tab
- it first tries the instance locator cache
- on cache miss, it falls back to scanning running instances through `/tabs`
- after resolution, it proxies the request to the owning bridge instance

This keeps the public server API stable while the bridge instances remain isolated.

Important limitation:

- this routing path is fully shaped around managed bridge-backed instances that expose loopback HTTP ports
- attached instances are registered and surfaced in the instance registry, but the normal tab-owner proxy path is not yet equally first-class for them

## Stop Flow

Stopping a managed instance is a server-owned lifecycle operation.

```mermaid
flowchart LR
    R["Stop Request"] --> S["Mark stopping"]
    S --> G["POST /shutdown to instance"]
    G --> W{"Exited?"}
    W -->|No| T["SIGTERM"]
    T --> K{"Exited?"}
    K -->|No| X["SIGKILL"]
    W -->|Yes| D["Remove from registry"]
    K -->|Yes| D
    X --> D
```

Current stop behavior:

- marks the instance as `stopping`
- tries graceful shutdown through the instance HTTP API
- falls back to process-group termination when needed
- releases the allocated port
- removes the instance from the registry and locator cache

For attached instances, there is no child process to kill; the orchestrator only removes its own registration state.

## Instance States

The main statuses surfaced today are:

- `starting`
- `running`
- `stopping`
- `stopped`
- `error`

The orchestrator also emits lifecycle events such as:

- `instance.started`
- `instance.stopped`
- `instance.error`
- `instance.attached`

## Relationship To Other Layers

- **Strategy layer** decides how shorthand requests are exposed or routed in server mode
- **Scheduler** is optional and sits above the same routed execution path
- **Bridge** owns browser state, tab state, and CDP execution
- **Profiles** provide persistent browser data on disk