Core Concepts
Selectors and Persist Keys
OpenSteer targets DOM nodes with element counters, CSS selectors, or saved `persist` keys.
Selectors and Persist Keys
OpenSteer has one targeting model across the SDK: every DOM action targets exactly one of element, selector, or persist.
element
Use the current snapshot counter.
await opensteer.click({ element: 3 });
await opensteer.input({ element: 5, text: "laptop" });
This is the fastest way to explore a page, but it only works against the current snapshot.
selector
Use a CSS selector directly.
await opensteer.click({ selector: "#submit" });
await opensteer.hover({ selector: "[data-testid='menu']" });
This is useful when you already know the selector and do not need a snapshot counter.
persist
Use a saved key that points to a previously learned deterministic path.
await opensteer.click({ persist: "primary call to action" });
await opensteer.input({
persist: "search input",
text: "laptop",
});
You usually create that key during exploration:
await opensteer.click({
element: 3,
persist: "primary call to action",
});
On the first run, OpenSteer resolves the element from the current page and saves the deterministic path. On later runs, persist reuses that saved path.
CLI behavior
The CLI DOM commands are positional and exploration-oriented:
opensteer click 3 --workspace demo --persist "primary call to action"
opensteer input 5 laptop --workspace demo --persist "search input"
The CLI uses the element you pass today and can save a persist key while doing it.
Persist-only DOM targeting is part of the SDK surface:
await opensteer.click({ persist: "primary call to action" });
Extraction uses the same idea
Extraction can also save a reusable descriptor:
await opensteer.extract({
persist: "page summary",
schema: {
title: { element: 2 },
url: { source: "current_url" },
},
});
const replayed = await opensteer.extract({
persist: "page summary",
});
Where descriptors are stored
Persisted DOM and extraction descriptors live under:
.opensteer/workspaces/<workspace>/registry/descriptors/
That storage is workspace-scoped, which is why workspace naming matters.
