Go SDK

The official Go SDK for Plasmate, with typed structs and SOM query functions.

Installation

go get github.com/nickel-org/plasmate-go

Requires Go 1.21+ and the plasmate binary on your PATH.

Quick Start

package main

import (
    "fmt"
    "log"

    plasmate "github.com/nickel-org/plasmate-go"
)

func main() {
    client := plasmate.NewClient()
    defer client.Close()

    som, err := client.FetchPage("https://example.com")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(som.Title)
    fmt.Printf("Regions: %d, Elements: %d\n", len(som.Regions), som.Meta.ElementCount)
}

Go Structs

`Som`

type Som struct {
    SOMVersion     string          `json:"som_version"`
    URL            string          `json:"url"`
    Title          string          `json:"title"`
    Lang           string          `json:"lang"`
    Regions        []Region        `json:"regions"`
    Meta           SomMeta         `json:"meta"`
    StructuredData *StructuredData `json:"structured_data,omitempty"`
}

`Region`

type Region struct {
    ID       string    `json:"id"`
    Role     string    `json:"role"`     // navigation, main, aside, header, footer, form, dialog, content
    Label    *string   `json:"label,omitempty"`
    Action   *string   `json:"action,omitempty"`
    Method   *string   `json:"method,omitempty"`
    Elements []Element `json:"elements"`
}

`Element`

type Element struct {
    ID       string        `json:"id"`
    Role     string        `json:"role"`     // link, button, text_input, textarea, select, checkbox, radio, heading, image, list, table, paragraph, section, separator
    Text     *string       `json:"text,omitempty"`
    Label    *string       `json:"label,omitempty"`
    Actions  []string      `json:"actions,omitempty"`
    Attrs    *ElementAttrs `json:"attrs,omitempty"`
    Children []Element     `json:"children,omitempty"`
    Hints    []string      `json:"hints,omitempty"`
}

`SomMeta`

type SomMeta struct {
    HTMLBytes        int `json:"html_bytes"`
    SOMBytes         int `json:"som_bytes"`
    ElementCount     int `json:"element_count"`
    InteractiveCount int `json:"interactive_count"`
}

Query Functions

`Parse(data)`

Parse raw JSON bytes into a Som struct.

som, err := plasmate.Parse(jsonBytes)

`FindByRole(som, role)`

Find all regions matching a given role.

navRegions := plasmate.FindByRole(som, "navigation")

`FindByID(som, id)`

Find a single element by its stable ID. Returns nil if not found.

el := plasmate.FindByID(som, "login-btn")
if el != nil {
    fmt.Println(*el.Text)
}

`FindByTag(som, tag)`

Find elements matching a tag/role string.

links := plasmate.FindByTag(som, "link")

`FindInteractive(som)`

Return all interactive elements.

interactive := plasmate.FindInteractive(som)
fmt.Printf("%d interactive elements\n", len(interactive))

`GetActionPlanIndex(som, enabledOnly...)`

Return compact action targets indexed by replay ids and grouped by role/action. Use this before prompt construction or replay validation when you only need a menu of enabled buttons, links, inputs, or one action type.

index := plasmate.GetActionPlanIndex(som, true)

buttons := index.ByRole["button"]
clickTargets := index.ByAction["click"]
planSelect := index.ByLabel["Plan"]

`FindActionTargetsByRole(som, role, enabledOnly...)`

Return compact action targets for one SOM role without scanning the full plan.

buttons := plasmate.FindActionTargetsByRole(som, "button", true)

`FindActionTargetsByAction(som, action, enabledOnly...)`

Return compact action targets exposing one action.

clicks := plasmate.FindActionTargetsByAction(som, "click", true)

`FindActionTargetByLabel(som, label)`

Resolve the first compact action target with an exact accessible label. Treat labels as human-facing recovery hints; store SOM ids, cache keys, HTML ids, or test ids for unattended replay.

target := plasmate.FindActionTargetByLabel(som, "Plan")

`FindByText(som, text)`

Find elements whose text content contains the given string (case-insensitive).

matches := plasmate.FindByText(som, "Sign in")

`FlatElements(som)`

Flatten all elements across all regions into a single slice.

all := plasmate.FlatElements(som)

`TokenEstimate(som)`

Estimate the LLM token count for the SOM (heuristic: SOMBytes / 4).

tokens := plasmate.TokenEstimate(som)
fmt.Printf("~%d tokens\n", tokens)

Client Usage

Creating a Client

// Default options
client := plasmate.NewClient()

// Custom binary path
client := plasmate.NewClient(plasmate.WithBinary("/usr/local/bin/plasmate"))

Stateless Methods

// Fetch a page and return SOM
som, err := client.FetchPage("https://example.com")

// Fetch with options
som, err := client.FetchPageWithOptions("https://example.com", plasmate.FetchOptions{
    Budget:     8000,
    JavaScript: true,
})

// Extract plain text
text, err := client.ExtractText("https://example.com")

Stateful Sessions

// Open a persistent page session
session, err := client.OpenPage("https://example.com")
// session.SessionID, session.Som

// Execute JavaScript
result, err := client.Evaluate(session.SessionID, "document.title")

// Click an element and get updated SOM
updatedSom, err := client.Click(session.SessionID, "login-btn")

// Close the session
err = client.ClosePage(session.SessionID)

Cleanup

err := client.Close()

The client is thread-safe with internal mutex protection. It communicates with the plasmate mcp subprocess over JSON-RPC 2.0 on stdio.