Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
39d0464
chore: update kernel-go-sdk to v0.107.0
kernel-internal[bot] Sep 16, 2026
a63dd37
Merge main into cli-coverage-update
kernel-internal[bot] Sep 17, 2026
74e93b3
chore: bump Go SDK to 51d7fb8 (v0.107.1-0.20260917184535)
kernel-internal[bot] Sep 17, 2026
627c950
chore: bump Go SDK to v0.108.0 (3556e00)
kernel-internal[bot] Sep 17, 2026
7a8a71e
chore: bump Go SDK to 6367486 and show org concurrency usage
kernel-internal[bot] Sep 17, 2026
6643d5d
Update Go SDK to 3038f83 and adopt ordered credential fields
kernel-internal[bot] Sep 17, 2026
7176b47
chore: bump Go SDK to 5cfcedd and document opaque AgentCard card IDs
kernel-internal[bot] Sep 17, 2026
0601cdf
chore: bump Go SDK to v0.109.0 (5c91a27)
kernel-internal[bot] Sep 17, 2026
086f25e
Merge main into cli-coverage-update
kernel-internal[bot] Sep 18, 2026
51d6810
Update SDK to c4dc2a2 and surface credential field labels
kernel-internal[bot] Sep 18, 2026
5c5dc62
chore: bump Go SDK to released v0.110.0 (a414a68)
kernel-internal[bot] Sep 18, 2026
d53e6ed
Merge main into cli-coverage-update
kernel-internal[bot] Sep 18, 2026
863ed39
chore: bump Go SDK to 6e379e6 (proxy_error raw_code)
kernel-internal[bot] Sep 18, 2026
46ca7ed
feat: Update Go SDK to dd9a4a4 and accept adyen checkout processor
kernel-internal[bot] Sep 21, 2026
345a60d
chore: bump Go SDK to 68c5100 (optimistic managed auth reauth)
kernel-internal[bot] Sep 21, 2026
b6f9f2a
chore: bump Go SDK to ca8d465 and surface managed auth completion times
kernel-internal[bot] Sep 21, 2026
e7efb10
feat: add --skill-mode to auth connections login, bump SDK
kernel-internal[bot] Sep 21, 2026
f3bd1bb
feat: add kernel search commands, bump Go SDK to 0554699
kernel-internal[bot] Sep 22, 2026
f50d037
chore: bump Go SDK to v0.111.0 (df8b441)
kernel-internal[bot] Sep 22, 2026
2806722
chore: bump Go SDK to 1ef7b7c
kernel-internal[bot] Sep 22, 2026
846f841
chore: bump Go SDK to 0584ea1
kernel-internal[bot] Sep 22, 2026
2cb6fc8
Merge main into cli-coverage-update
kernel-internal[bot] Sep 23, 2026
dfcd804
Update Go SDK to a9ee57c and filter telemetry events by type server-side
kernel-internal[bot] Sep 23, 2026
adf8f7d
Update Go SDK to b50814f and add profile flags to pool acquire
kernel-internal[bot] Sep 23, 2026
0ca9f8c
Remove duplicate search command registration left by merge
kernel-internal[bot] Sep 23, 2026
ab1c8c2
Update Go SDK to 8e055e1 and show Search entitlement in org entitlements
kernel-internal[bot] Sep 24, 2026
f3b9f8e
Update Go SDK to ffc38db and add --proxy-route to browsers create
kernel-internal[bot] Sep 24, 2026
3e77f83
Update Go SDK to 47c1310 and add WebMCP custom-tools commands
kernel-internal[bot] Sep 24, 2026
572718b
Update Go SDK to v0.112.0 (247bcf1)
kernel-internal[bot] Sep 24, 2026
10d4416
Merge main into cli-coverage-update
kernel-internal[bot] Sep 26, 2026
39a0426
Update Go SDK to 140c57d and fix merge fallout from main
kernel-internal[bot] Sep 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 73 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Kernel provides sandboxed, ready-to-use Chrome browsers for browser automations
- Invoke app actions (sync or async) and stream logs
- Create, list, view, and delete managed browser sessions
- Get a live view URL for visual monitoring and remote control
- Search the web across providers and retrieve page content for results

## Installation

Expand Down Expand Up @@ -335,8 +336,17 @@ populated, not that login succeeded. `fill` requires an already-open page and ne
navigates or submits it. Optional `page_url` selects the exact page; cards require it.
Do not automatically retry failed/unknown fills or fall back to aliases.

Create specs list `fields` as an ordered array. Each entry carries a stable `name`
(letters, digits, and underscores, starting with a letter) that keys values, updates,
and fills. Order is preserved: list fields in the same top-to-bottom order as the
website, because the collection form renders that order unchanged. An optional `label`
supplies non-secret display text for that field on the collection form; it never
affects value keys, updates, or fills. Use a single trimmed line of at most 128 UTF-8
bytes, and it is returned as metadata in `get`/`list` output.

Use `credentials update <vault> <key> --version <version> --spec-file changes.json`
with a spec such as `{"fields":{"password":{"value":"replacement"}}}`. Keep actual
with a spec such as `{"fields":{"password":{"value":"replacement"}}}`; update specs key
`fields` by name rather than using the ordered array. Keep actual
secrets in protected files or stdin, never shell arguments. Omission preserves values;
null or an empty string clears supported fields, including required text/email/password fields (returning them to pending collection). The form still requires nonempty required inputs. Field definitions cannot change. Stale versions fail,
without retries. `items invoke <vault> <key> collect` reopens the full form without
Expand Down Expand Up @@ -597,14 +607,21 @@ kernel vaults items get user-123 order-1 --wait 60 -o json
this vault attached. `merchant_origin` is the canonical HTTPS origin of the top-level
merchant document, not a processor iframe; HTTP localhost is allowed for tests.

Optional `psp` selects the tokenization processor: `square`, `braintree`, `worldpay`,
`bambora`, or `mercado_pago`. Omit it for Square; non-Square processors require
Optional `psp` selects the checkout processor: `square`, `braintree`, `worldpay`,
`bambora`, `mercado_pago`, or `adyen`. Omit it for Square; non-Square processors require
multi-processor preparation enablement. `environment` is `production`, `sandbox`, or
`shared`: use `production` or `sandbox` for Square, Braintree and Worldpay, and `shared`
for Bambora and Mercado Pago. Shared endpoints do not establish test mode; merchant
`shared`: use `production` or `sandbox` for Square, Braintree, Worldpay and Adyen, and
`shared` for Bambora and Mercado Pago. Shared endpoints do not establish test mode; merchant
credentials and configuration determine processor test mode, independently of the
AgentCard credential mode.

`adyen` supports fresh-card Sessions requests on Adyen hosts only. Fill the public dummy
card fields rather than vault aliases, and keep the approval page open through device
handoff, including Adyen encryption. The unique armed preparation is associated with the
next eligible request from the declared browser and merchant origin; competing preparations
are rejected. Adyen device approval and browser `Authorised` responses are not capture or
fulfillment evidence.

Keep the approval page open. Poll until the item's status is `ready_to_submit`, then
submit native Pay before `state.preparation.expires_at`. Readiness lasts at most 30
seconds, and polling does not extend it. The CLI displays the preparation ID, status,
Expand Down Expand Up @@ -951,6 +968,13 @@ Destinations are the OTLP/HTTP endpoints sessions export to. They belong to the
- Prints the tool's `output` as pretty JSON on completion; tool errors and cancellations exit non-zero
- `awaiting_submission` is successful but warns that a non-autosubmit declarative form was filled, not submitted. Inspect the form, obtain any required confirmation, then submit through Playwright or computer interaction instead of invoking the tool again
- Invocations are never retried automatically. A 504 `outcome_unknown` error prints the code, invocation ID, and message and exits non-zero. The tool may already have had side effects; verify the outcome before invoking it again
- `kernel browsers webmcp custom-tools list <id-or-name>` - List registered custom tools with their generated ID, namespace, kind, URL patterns, and metadata
- `-o json` - Output the raw response
- `kernel browsers webmcp custom-tools add <id-or-name> --namespace <ns> --source '<js>'` - Atomically add a namespaced batch of page-backed or CDP-backed custom tools
- `--source <js>` or `--source-file <path>` - JavaScript expression evaluating to a non-empty array of tool definitions (URL matchers, tool metadata, execute functions); mutually exclusive. Use `--source-file -` to read stdin
- `--force-overwrite-namespace` - Atomically replace every existing tool in the namespace
- `-o json` - Output the raw response
- `kernel browsers webmcp custom-tools remove <id-or-name> <tool-id>` - Remove one custom tool by generated ID (in-progress invocations are not canceled)

- `kernel browsers webmcp custom-tools list <id-or-name>` - List all registered custom tools, even when no page currently matches
- Displays ID, namespace, kind (`page` or `cdp`), name, and URL patterns
Expand Down Expand Up @@ -1209,6 +1233,50 @@ Automated authentication for web services. The `run` command orchestrates the fu
- `--default-project-max-concurrent-sessions <n>` - Default maximum concurrent browsers for projects without an explicit override (`0` to remove the default)
- `--output json`, `-o json` - Output raw JSON object

### Search

- `kernel search <query>` - Search the web through Kernel's search providers
- `--country <code>` - ISO 3166-1 alpha-2 search locale preference
- `--language <tag>` - BCP 47 search language preference
- `--max-results <n>` - Requested result count, 1-100 (clamped to the serving provider's cap)
- `--recency <window>` - Relative search window: `hour`, `day`, `week`, `month`, or `year`
- `--safe-search <level>` - Safety preference: `off`, `moderate`, or `strict`
- `--start-date <YYYY-MM-DD>` / `--end-date <YYYY-MM-DD>` - Inclusive publication-date bounds (`--recency` takes precedence)
- `--include-domains <hosts>` / `--exclude-domains <hosts>` - Hostname preferences, matching a hostname and its subdomains
- `--strict-params` - Require every supplied portable parameter to be honored exactly instead of approximated
- `--include-raw` - Include untouched provider payloads in the response's raw fields
- `--timeout-ms <ms>` - Overall deadline across search attempts and inline retrieval
- `--content` - Retrieve page content for each result using portable defaults
- `--show-content` - Print the extracted content text for each result (implies `--content`)
- `--content-source <source>` - Retrieval source: `auto`, `provider`, or `browser`
- `--content-format <format>` - Extracted content format: `markdown` or `text`
- `--content-max-chars <n>` - Per-result Unicode character limit after extraction
- `--content-max-age-hours <n>` - Maximum acceptable age of cached page content; `0` forces a live fetch
- `--content-timeout-ms <ms>` - Per-result retrieval deadline
- `--content-browser-id <id>` - Retrieve through an existing browser session (requires `--content-source browser`)
- `--content-browser-mode <mode>` - Browser retrieval mode: `curl` or `render`
- `--provider <slug>` - Pin a single provider (`brave`, `exa`, `perplexity`, `context`, `parallel`, `valyu`, `octen`, `you`, `tavily`, `serpapi`)
- `--fallback-providers <slugs>` - Ordered provider chain to try in turn
- `--fallback-on <outcomes>` - Outcomes that advance to the next provider: `error`, `timeout`, `empty`
- `--provider-options <json>` - Provider-native options as a JSON object keyed by provider slug
- `--output json`, `-o json` - Output raw JSON object
- `kernel search get <id>` - Re-read a retained search without calling a provider or incurring cost
- `--show-content` - Print the extracted content text for each result
- `--output json`, `-o json` - Output raw JSON object
- `kernel search providers` - List providers, result caps, and content capabilities
- `--slug <slug>` - Filter to a single provider; also prints its portable-parameter support matrix and notes
- `--output json`, `-o json` - Output raw JSON array
- `kernel search contents <id>` - Deferred content retrieval for a retained search
- `--result-ids <ids>` - Result IDs from the retained search, in the desired response order
- `--limit <n>` - Number of results to fetch starting from rank 1 (mutually exclusive with `--result-ids`)
- `--timeout-ms <ms>` - Overall deadline across all selected results
- Accepts the same `--content-*` flags as `kernel search`
- This endpoint is reserved and returns 404 until deferred retrieval ships; use `kernel search --content` for inline retrieval

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deferred search contents documented

Medium Severity

The README adds kernel search contents for deferred content retrieval, including flags and a note that the endpoint returns 404 until it ships. Deferred retrieval is unavailable and must not be exposed; the subcommand is also not implemented.

Fix in Cursor聽Fix in Web

Triggered by learned rule: Search CLI: no-retry Execute; pass-through JSON; document schema

Reviewed by Cursor Bugbot for commit dfcd804. Configure here.


Searches are retained for 24 hours. Omitting the strategy flags lets Kernel pick an
eligible provider; portable filters a provider cannot honor are approximated or
dropped and reported as warnings unless `--strict-params` is set.

## Examples

### Create a new app
Expand Down
31 changes: 30 additions & 1 deletion cmd/auth_connections.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ type AuthConnectionLoginInput struct {
Region string
Stealth BoolFlag
RecordSession BoolFlag
SkillMode string
Telemetry string
TelemetryCdpExclude string
TelemetryExport string
Expand Down Expand Up @@ -794,6 +795,20 @@ func (c AuthConnectionCmd) Delete(ctx context.Context, in AuthConnectionDeleteIn
return nil
}

// parseSkillModeFlag validates the --skill-mode value against the modes the API
// accepts for a login, so a typo fails locally instead of starting a flow with
// the wrong skill behavior.
func parseSkillModeFlag(mode string) (kernel.AuthConnectionLoginParamsSkillMode, error) {
switch kernel.AuthConnectionLoginParamsSkillMode(mode) {
case kernel.AuthConnectionLoginParamsSkillModeEnabled:
return kernel.AuthConnectionLoginParamsSkillModeEnabled, nil
case kernel.AuthConnectionLoginParamsSkillModeDisabled:
return kernel.AuthConnectionLoginParamsSkillModeDisabled, nil
default:
return "", fmt.Errorf("invalid --skill-mode value: %s (must be one of enabled, disabled)", mode)
}
}

func (c AuthConnectionCmd) Login(ctx context.Context, in AuthConnectionLoginInput) error {
if err := validateJSONOutput(in.Output); err != nil {
return err
Expand Down Expand Up @@ -825,6 +840,14 @@ func (c AuthConnectionCmd) Login(ctx context.Context, in AuthConnectionLoginInpu
params.RecordSession = kernel.Opt(in.RecordSession.Value)
}

if in.SkillMode != "" {
mode, err := parseSkillModeFlag(in.SkillMode)
if err != nil {
return err
}
params.SkillMode = mode
}

if in.Telemetry != "" || in.TelemetryCdpExclude != "" || in.TelemetryExport != "" {
t, err := buildManagedAuthTelemetryParam(in.Telemetry, in.TelemetryCdpExclude, in.TelemetryExport, false)
if err != nil {
Expand Down Expand Up @@ -1069,7 +1092,7 @@ func (c AuthConnectionCmd) Timeline(ctx context.Context, in AuthConnectionTimeli
return nil
}

tableData := pterm.TableData{{"Timestamp", "Type", "Status", "Step", "Browser Session", "Telemetry", "Details"}}
tableData := pterm.TableData{{"Timestamp", "Completed", "Type", "Status", "Step", "Browser Session", "Telemetry", "Details"}}
for _, e := range events {
details := e.ErrorMessage
if details == "" {
Expand All @@ -1087,6 +1110,9 @@ func (c AuthConnectionCmd) Timeline(ctx context.Context, in AuthConnectionTimeli
}
tableData = append(tableData, []string{
util.FormatLocal(e.Timestamp),
// Absent (dashed out) for in-progress attempts, health checks, and
// older attempts recorded before completion times were persisted.
util.FormatLocal(e.CompletedAt),
string(e.Type),
string(e.Status),
string(e.Step),
Expand Down Expand Up @@ -1381,6 +1407,7 @@ func init() {
authConnectionsLoginCmd.Flags().String("region", "", "Geographic region override for this login: 'us-east', 'eu-west', or 'ap-southeast'")
authConnectionsLoginCmd.Flags().Bool("stealth", true, "Override stealth mode for this login's browser session; use --stealth=false to disable")
authConnectionsLoginCmd.Flags().Bool("record-session", false, "Override whether this login's browser session is recorded; use --record-session=false to disable")
authConnectionsLoginCmd.Flags().String("skill-mode", "", "Whether this login reads and writes learned domain skills: 'enabled' (default) or 'disabled'. Automatic reauths inherit the selected mode until a later accepted login sets enabled or omits the flag")
authConnectionsLoginCmd.Flags().String("telemetry", "", "Telemetry override for this login only, merged onto the connection's config: --telemetry=all, --telemetry=off, or --telemetry=console,network")
authConnectionsLoginCmd.Flags().String("telemetry-export-otlp", "", "Export override for this login only: an OTLP destination ID or name; --telemetry-export-otlp=off disables export for this login. Naming a destination requires passing --telemetry in the same command, since export and capture are validated together")
authConnectionsLoginCmd.Flags().String("telemetry-cdp-exclude", "", "Leave the named CDP methods out of control telemetry's cdp_command events, comma-separated (e.g. Input.dispatchMouseEvent,Page.captureScreenshot); --telemetry-cdp-exclude=none clears the list. Excluded commands are still relayed to the browser, they just produce no event")
Expand Down Expand Up @@ -1600,6 +1627,7 @@ func runAuthConnectionsLogin(cmd *cobra.Command, args []string) error {
proxyName, _ := cmd.Flags().GetString("proxy-name")
proxyMode, _ := cmd.Flags().GetString("proxy-mode")
region, _ := cmd.Flags().GetString("region")
skillMode, _ := cmd.Flags().GetString("skill-mode")
telemetry, _ := cmd.Flags().GetString("telemetry")
telemetryCdpExclude, _ := cmd.Flags().GetString("telemetry-cdp-exclude")
telemetryExport, _ := cmd.Flags().GetString("telemetry-export-otlp")
Expand All @@ -1614,6 +1642,7 @@ func runAuthConnectionsLogin(cmd *cobra.Command, args []string) error {
Region: region,
Stealth: readBoolFlag(cmd.Flags(), "stealth"),
RecordSession: readBoolFlag(cmd.Flags(), "record-session"),
SkillMode: skillMode,
Telemetry: telemetry,
TelemetryCdpExclude: telemetryCdpExclude,
TelemetryExport: telemetryExport,
Expand Down
47 changes: 46 additions & 1 deletion cmd/auth_connections_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"net/http/httptest"
"os"
"testing"
"time"

"github.com/kernel/cli/pkg/util"
"github.com/kernel/kernel-go-sdk"
Expand Down Expand Up @@ -1223,7 +1224,8 @@ func TestTimeline_RendersEventsAndPagination(t *testing.T) {
"type": "login",
"status": "SUCCESS",
"browser_session_id": "browser_1",
"telemetry_captured": true
"telemetry_captured": true,
"completed_at": "2026-09-21T12:00:00Z"
}`), &loginEvent))
fake := &FakeAuthConnectionService{
TimelineFunc: func(ctx context.Context, id string, query kernel.AuthConnectionTimelineParams, opts ...option.RequestOption) (*pagination.OffsetPagination[kernel.ManagedAuthTimelineEvent], error) {
Expand Down Expand Up @@ -1252,6 +1254,9 @@ func TestTimeline_RendersEventsAndPagination(t *testing.T) {
// Telemetry capture is reported for events that have a browser session.
assert.Contains(t, out, "Telemetry")
assert.Regexp(t, `browser_1.*yes`, out)
// completed_at is shown for terminal attempts and dashed out otherwise.
assert.Contains(t, out, "Completed")
assert.Contains(t, out, util.FormatLocal(time.Date(2026, 9, 21, 12, 0, 0, 0, time.UTC)))
// The third event is truncated off the page.
assert.NotContains(t, out, "health_check")
assert.Contains(t, out, "Has more: yes")
Expand Down Expand Up @@ -1390,3 +1395,43 @@ func TestAuthConnectionsGet_TelemetryRowOmittedWhenOff(t *testing.T) {
require.NoError(t, c.Get(context.Background(), AuthConnectionGetInput{ID: "conn-1"}))
assert.NotContains(t, outBuf.String(), "Browser Telemetry")
}

func TestLogin_SkillMode(t *testing.T) {
capturePtermOutput(t)
var captured kernel.AuthConnectionLoginParams
fake := &FakeAuthConnectionService{
LoginFunc: func(ctx context.Context, id string, body kernel.AuthConnectionLoginParams, opts ...option.RequestOption) (*kernel.LoginResponse, error) {
captured = body
return &kernel.LoginResponse{ID: id}, nil
},
}
c := AuthConnectionCmd{svc: fake}
require.NoError(t, c.Login(context.Background(), AuthConnectionLoginInput{ID: "auth_1", SkillMode: "disabled"}))
assert.Equal(t, kernel.AuthConnectionLoginParamsSkillModeDisabled, captured.SkillMode)
}

// Omitting --skill-mode leaves the field unset, so the API keeps its default of
// enabled rather than the CLI pinning a mode the user never asked for.
func TestLogin_SkillModeOmitted(t *testing.T) {
capturePtermOutput(t)
var captured kernel.AuthConnectionLoginParams
fake := &FakeAuthConnectionService{
LoginFunc: func(ctx context.Context, id string, body kernel.AuthConnectionLoginParams, opts ...option.RequestOption) (*kernel.LoginResponse, error) {
captured = body
return &kernel.LoginResponse{ID: id}, nil
},
}
c := AuthConnectionCmd{svc: fake}
require.NoError(t, c.Login(context.Background(), AuthConnectionLoginInput{ID: "auth_1"}))
assert.Empty(t, string(captured.SkillMode))
}

func TestLogin_InvalidSkillModeErrors(t *testing.T) {
capturePtermOutput(t)
c := AuthConnectionCmd{svc: &FakeAuthConnectionService{}}

err := c.Login(context.Background(), AuthConnectionLoginInput{ID: "auth_1", SkillMode: "mars"})

require.Error(t, err)
assert.Contains(t, err.Error(), "invalid --skill-mode value")
}
Loading
Loading