Vibium Extension Commands: Custom BiDi Protocol Extensions
How WebDriver BiDi Supports Extensions
The WebDriver BiDi specification explicitly allows implementations to define custom commands:
"An implementation may define extension modules. These must have a module name that contains a single colon ':' character."
Vibium defines three extension commands that are handled by the Go binary (clicker), not forwarded to Chrome:
| Command | Parameters | Description |
|---|---|---|
vibium:find |
context, selector, timeout |
Wait for element to exist |
vibium:click |
context, selector, timeout |
Wait for actionable, then click |
vibium:type |
context, selector, text, timeout |
Wait for actionable, then type |
Message Flow
Standard BiDi Command (Pass-Through)
Client Clicker Proxy Chrome
│ │ │
│── browsingContext.navigate ──►│ │
│ │── browsingContext.navigate ──►│
│ │◄── success ───────────────────│
│◄── success ───────────────────│ │
Standard BiDi commands pass straight through the proxy.
Vibium Extension Command (Intercepted)
Client Clicker Proxy Chrome
│ │ │
│── vibium:click ──────────►│ │
│ │ │
│ │ ┌─ ACTIONABILITY LOOP ──┐ │
│ │ │ │ │
│ │──│─ script.callFunction ─│──►│ (visible check)
│ │◄─│─ result ──────────────│───│
│ │──│─ script.callFunction ─│──►│ (stable check T1)
│ │◄─│─ result ──────────────│───│
│ │ │ sleep 50ms │ │
│ │──│─ script.callFunction ─│──►│ (stable check T2)
│ │◄─│─ result ──────────────│───│
│ │──│─ script.callFunction ─│──►│ (receivesEvents)
│ │◄─│─ result ──────────────│───│
│ │──│─ script.callFunction ─│──►│ (enabled)
│ │◄─│─ result ──────────────│───│
│ │ └───────────────────────┘ │
│ │ │
│ │── input.performActions ─────►│ (actual click)
│ │◄── success ──────────────────│
│ │ │
│◄── success ───────────────│ │
The proxy intercepts vibium:* commands, runs multiple BiDi sub-commands against Chrome, and returns a single success/error to the client.
Implementation Details
Request Format
{
"id": 1,
"method": "vibium:click",
"params": {
"context": "browsing-context-id-123",
"selector": "button.submit",
"timeout": 30000
}
}
Success Response
{
"id": 1,
"type": "success",
"result": {
"clicked": true
}
}
Error Response (Timeout)
{
"id": 1,
"type": "error",
"error": {
"error": "timeout",
"message": "timeout after 30s waiting for 'button.submit': check 'ReceivesEvents' failed — obscured by div.modal-overlay"
}
}
Code Location in the Repository
Client side (sending commands):
clients/javascript/src/vibe.ts#L69—client.send('vibium:find', { ... })
Server side (handling commands):
clicker/internal/proxy/router.go#L150— Router dispatchesvibium:findto handlerclicker/internal/proxy/router.go#L303—handleVibiumFind()implementation
The Router Pattern
// Simplified from router.go
func (r *Router) OnClientMessage(msg []byte) {
var req struct {
Method string `json:"method"`
// ...
}
json.Unmarshal(msg, &req)
switch req.Method {
case "vibium:find":
r.handleVibiumFind(req)
case "vibium:click":
r.handleVibiumClick(req)
case "vibium:type":
r.handleVibiumType(req)
default:
// Standard BiDi command — forward to Chrome
r.forwardToChrome(msg)
}
}
Adding Your Own Extension Command
If you needed a custom command (e.g., vibium:drag):
- Client sends
{"method": "vibium:drag", "params": {...}} - Add a case in
router.go'sOnClientMessageswitch - Implement handler that uses standard BiDi commands internally
- Call
sendSuccess()orsendError()to respond
Why This Architecture Matters
For Clients: Simplicity
The JavaScript client's click implementation is trivial:
async click(options?: { timeout?: number }): Promise<void> {
await this.client.send('vibium:click', {
context: this.context,
selector: this.selector,
timeout: options?.timeout,
});
}
No retry loops, no actionability checks, no complex state management. Just send a command and wait.
For the CLI: Same Simplicity
When you run vibe-check click "button", the CLI:
- Connects to the daemon's WebSocket
- Sends
vibium:clickwith the selector - Waits for success or error
- Prints result and exits
The CLI is just another BiDi client.
For the Skill: Maximum Token Efficiency
The agent runs Bash("vibe-check click 'button'") and gets back either:
- Exit code 0 + minimal output (success)
- Exit code 1 + descriptive error (failure)
No JSON schema overhead. No accessibility trees. Just a shell command and its output.
Comparison with Playwright's Approach
| Aspect | Playwright | Vibium |
|---|---|---|
| Protocol | CDP (Chrome DevTools Protocol) | WebDriver BiDi |
| Extension mechanism | Not standardized (CDP is Chrome-internal) | W3C standard extension points |
| Actionability location | Client library | Server proxy |
| Cross-browser | Via protocol abstraction layer | Via BiDi standard (native) |
| Custom commands | Library methods | BiDi extension commands |
Vibium's approach is more aligned with web standards. As BiDi matures and more browsers implement it natively, Vibium's protocol extensions can potentially be standardized.
Interview Talking Point
"Vibium extends the WebDriver BiDi protocol with custom commands —
vibium:find,vibium:click,vibium:type— using the spec's official extension mechanism. The Go binary acts as a BiDi proxy: standard commands pass through to Chrome, whilevibium:*commands are intercepted and handled server-side. A singlevibium:clickon the wire triggers a multi-step actionability loop — five checks in a polling loop, then the actual click via BiDi'sinput.performActions. This means clients send one message and get one response, with all the complexity hidden in the proxy. It's a clean separation of concerns: the protocol handles transport, the proxy handles intelligence, the client handles UX."