Verified web data for agents — from a signed catalog, or built on demand.
Install a maintained tool for the site and call it. No tool yet? klura builds one from a real session, and it gets the same declared contract. It all runs on your machine.
You want the top GitHub repositories matching "web scraping". Or every product on a search page. Normally that means writing a scraper, then rewriting it the next time the site changes.
klura skips that. Someone has already built and maintained a tool for the site, and you install it:
npm install -g @klura/runtime
klura install github
klura call github.search_repositories --input '{"query":"web scraping"}'You get back structured data, checked against the shape the tool promised. Not HTML to parse.
search → inspect → install → call once, or run a bounded scrape
Not in the catalog? Point klura at the site. It drives a real session, records what the page actually does, and turns that into a tool with the same declared origins, request budget, and output shape as every catalog tool. You can use it locally right away, or export it and open a pull request; after review it is signed into the catalog for everyone. That is how the catalog grows — see Advanced authoring.
Two ways to use a tool. call does one read and hands you one verified result. run collects a bounded set into a file — it has hard limits on items, pages, requests, and time, and you can leave it running, check on it, cancel it, or resume it.
It runs on your machine. The tool, the browser, the traffic to the site, and the output all stay local. No account, no LLM key, nothing executing on someone else's server. Inside a company that counts twice: what you look up and what comes back never pass through a third-party scraping vendor, and there is no external service to put through procurement or a data-processing review.
Tools say what they will do before they do it. Every tool declares which domains it may reach, how many requests it may make, and what its output looks like. You can read all of that with klura show before installing. The runtime holds it to that declaration.
Nothing counts as success just because it returned. A 200 response, or an empty list, means nothing on its own — sites serve error pages and empty shells with a 200 all the time. The runtime only reports success when the data matches what the tool said it would return.
You pick the version. The catalog is a signed index hosted on GitHub. You choose what to install, and an installed tool never changes underneath you.
Companies can use it internally for free. klura is source-available under BUSL-1.1. Running it on your own machines and inside your company — including for ordinary commercial work — is covered by the Additional Use Grant at no cost, so a team can put it into production without a purchase. The line it draws is reselling: you may not offer klura to third parties as a hosted service or API, or build a competing service on it. Full terms in LICENSE; for a commercial license that lifts those limits, hello@klura.ai.
Quick Start · Advanced Authoring · LIFT · Self-Healing · Map Mode · Benchmarks · Under the Hood · Use Cases · Legal & ToS · Docs · Get Involved
npm install -g @klura/runtime
klura search products
klura show <package[.capability]>
klura install <package[@version]>
klura call <package.capability> --input '{"...":"..."}'
klura run <package.capability> --input '{"...":"..."}' --output results.ndjsoncall returns one typed, verified read result. run writes a bounded local collection and can be detached, inspected, cancelled, or explicitly resumed under the exact installed package digest. klura factory --help is the separate advanced authoring surface; it is never entered automatically when a catalog search has no match.
Klura also works with Codex, the ChatGPT desktop app, Claude Code, Claude Desktop, Cursor, Windsurf, OpenClaw, and other MCP hosts. The same server exposes the consumer tools first and discovery tools only for explicit authoring.
The Codex CLI, IDE extension, and ChatGPT desktop app share one MCP configuration:
codex mcp add klura -- npx -y @klura/mcpRestart the host after registering.
The fastest path is the CLI:
claude mcp add klura -- npx -y @klura/mcpThat registers klura at user scope. To install per-project, drop it into .mcp.json at the repo root:
{
"mcpServers": {
"klura": {
"command": "npx",
"args": ["-y", "@klura/mcp"]
}
}
}You can also edit ~/.claude.json directly, but claude mcp add is the supported path. After install, run claude mcp list to confirm klura is registered.
These hosts share the same MCP config shape. Drop the snippet into the host's MCP config file (e.g. claude_desktop_config.json for Claude Desktop) and restart the client:
{
"mcpServers": {
"klura": {
"command": "npx",
"args": ["-y", "@klura/mcp"]
}
}
}If you're working on klura itself, link the local build into your global path so MCP hosts and the klura CLI both see your changes:
cd runtime
npm install
npm run build
npm linkAfter every code change, re-run npm run build and restart the daemon: klura restart-runtime --force (or pkill -f 'klura.*daemon').
When a maintained package does not exist and you explicitly want to author one, klura can run its discovery/factory workflow with an optional LLM provider:
npm install -g @klura/runtime @klura/agent-claude-code # or @klura/agent-openai
klura chat
> message Adam in the team chatklura chat is a REPL over the factory tools exposed through MCP. claude-code reuses your Claude Code login; openai supports OpenAI and compatible endpoints such as NVIDIA, Together, Groq, and vLLM:
klura chat --provider claude-code
klura chat --provider openai --model gpt-5Settings live in the agent block of ~/.klura/config.json. For an OpenAI-compatible provider, set the API key there as agent.api_key — or, if you'd rather keep it out of the file (CI, shared machines), in the KLURA_AGENT_API_KEY environment variable. claude-code needs neither.
Sessions are transcribed to ~/.klura/chat-logs/chat-<timestamp>.jsonl; opt out with agent.log_transcript: false or --no-transcript.
klura execute gets a self-healing mode. klura execute <platform> <capability> --agent runs the saved strategy with no LLM cost when it succeeds; if it fails, the LLM picks up the live session and re-drives to repair the strategy:
klura execute team-chat send_message --args '{"to":"Adam"}' --agentExternal MCP hosts supply their own LLM. Standalone providers: @klura/agent-claude-code, @klura/agent-openai.
Browser agents are slow because they keep using the UI as the interface.
Klura treats the UI as a discovery step.
1. First run
The agent uses the browser normally.
2. Capture
Klura records traffic, cookies, page state, and action history.
3. Lift
Klura analyzes the trace and learns the underlying request or script.
4. Later runs
The saved strategy executes directly.
The saved output is not “agent memory.” It is executable strategy data built from the observed session.
LIFT means Learn Interface From Traffic.
It is the analysis pass that turns a captured browser session into a reusable strategy.
Before LIFT: After LIFT:
click button POST /api/messages
wait for UI update {"text": "hello"}
read confirmation ~200ms, 0 LLM tokens
A saved fetch strategy looks like this:
{
"strategy": "fetch",
"method": "POST",
"baseUrl": "https://chat.so",
"endpoint": "/api/conversations/v1/send",
"prerequisites": [
{
"kind": "capability",
"capability": "list_conversations",
"args": {
"name": "{{recipient}}"
},
"vars": {
"thread_id": "conversations[0].id"
}
}
],
"body": {
"to": "{{thread_id}}",
"text": "{{text}}"
},
"auth": {
"type": "session-cookie"
}
}On later runs, klura reads this strategy, resolves prerequisites, fills placeholders from the call arguments, and fires the request directly.
Strategies are saved as ordinary JSON files under:
~/.klura/skills/<platform>/
See REFERENCE.md for the full schema and REFERENCE.md#capability-prereq for prerequisite handling.
Klura saves the simplest strategy that actually works.
| Tier | Strategy | Used when |
|---|---|---|
| T0 | fetch |
A direct HTTP or WebSocket call is enough |
| T1 | page-script |
The page must run JavaScript to build, sign, or dispatch the request |
| T2 | recorded-path |
The safest available path is replaying the UI |
The tier reflects where the saved code runs:
fetchis a static templated HTTP call, fired from Node. Possible when every input — body, headers, tokens — can be reconstructed without the page.page-scriptruns JavaScript inside the live, already-authenticated browser tab. It can call functions the site itself defines: request signers, header rotators, MQTT codecs, WebSocket encoders, the in-page fetch wrapper. That makes lift possible for sites where the real request only exists as the output of in-page code, with no way to reproduce it from outside.recorded-pathreplays UI actions through the browser driver. Slower, but works when the request can't be cleanly isolated.
If a site cannot be lifted cleanly to fetch or page-script, klura still saves a recorded-path.
That is slower than a direct API call, but still avoids replanning the page from scratch. The same skill can later be re-lifted into a faster tier.
Websites change. Endpoints move. Tokens rotate. Response shapes drift.
Klura treats those as repairable failures.
When a saved strategy fails, klura classifies the failure:
| Failure type | What happens |
|---|---|
| Structural | Klura returns a clear error the agent can act on |
| Stale strategy | Klura routes back through capture and LIFT to patch the skill |
| Auth or session issue | Klura asks for the minimum required human help |
The goal is not silent retries. The goal is loud, structured failure and repair.
You do not need to start with a specific task.
Klura can scout a site first.
map this CRM with klura
The agent walks the surface area — pages, forms, settings, search, account flows — while klura records what it sees in a platform logbook.
The logbook lives under:
~/.klura/workdir/<platform>/
It stores things like:
- URL graph nodes
- form observations
- observed capabilities
- page notes
- useful surface-area hints for future sessions
No strategy is saved in map mode. Mutating actions require explicit consent.
The next real task starts with klura already familiar with the platform.
See docs/logbook.md.
The UI is the human layer over requests, tokens, state, and event streams. Klura captures that lower layer once and reuses it.
| Browser agent | Klura | |
|---|---|---|
| First run | Browser exploration | Browser exploration + network capture |
| Learning step | None | Optional LIFT pass |
| Later runs | Browser exploration again | Saved strategy |
| Tokens | Paid every run | Paid once, then zero in runtime |
| Latency | Seconds per UI step | Direct strategy execution |
The agent keeps judgment; the runtime takes over once execution becomes mechanical.
Each live-site task runs once with raw Playwright and once with an empty klura skill directory. After discovery, the saved strategy is executed directly.1
| Task | Result requirement | Plain browser agent2 | klura cold3 | Runtime replay4 |
|---|---|---|---|---|
| IKEA stock availability | Stock evidence for all four Berlin stores | 2m 17s | 9m 43s | 1.14s |
| ASOS filtered search | Five products plus both selected facets | 1m 35s | 6m 57s | 67.9ms |
| Airbnb search | Five Berlin stays with exact dates and guest count | 2m 48s | 13m 19s | 2.17s |
| Amazon product search | Top-three titles, prices, and ASINs/URLs | 3m 05s | 6m 52s | 3.46s |
ASOS replays with fetch; IKEA, Airbnb, and Amazon use page-script. Replay is the median of five sequential executions, all validated against the requested content rather than HTTP status alone.
Klura is built around a few constraints:
- Keep the LLM in charge of judgment.
- Keep the runtime boring where possible.
- Never silently accept broken strategies.
- Prefer real observed traffic over guesses.
- Fall back safely when a clean lift is not possible.
The runtime provides tools, captures data, validates output, executes strategies, and handles recovery.
The agent performs the reasoning: deciding what task is being done, choosing capabilities, composing prerequisites, and resolving ambiguity.
There is no heavy workflow engine. Capability composition happens in the agent turn, where user context already lives.
Example:
message Bob in team chat
may compose:
list_conversations(name="Bob")
send_message(thread_id=..., text=...)
The runtime executes the saved pieces.
Every saved strategy passes a structural audit before it hits disk.
The audit checks for problems like:
- dynamic values baked into static requests
- missing arguments
- missing auth assumptions
- weak or non-generalized selectors
- response-shape mismatches
- unsafe endpoint behavior
Issues are batched into one rejection so the agent can fix everything in one retry.
Browser sessions persist between runs.
Cookies, login state, and storage stay warm because the daemon outlives any single conversation. A site that asks for 2FA once a week should not require login every time an agent starts a new task.
Klura tracks estimated token lifetimes and refreshes before expiry when possible.
The goal is to avoid the common failure mode where long-running automation fails only after a CSRF token, nonce, or session value has already expired.
Some sites work over plain Node fetch.
Others reject anything that does not look like the real browser stack.
Klura picks the execution path per request and can fall back to an in-browser path when needed.
Klura supports listener-style capabilities for push streams:
- WebSocket
- Server-Sent Events
- polling feeds
Saved skills like on_new_message are first-class.
Some interruptions need a human:
- CAPTCHA
- 2FA
- “confirm this is you”
- password prompts
- account recovery walls
Klura opens a live viewer of the in-progress browser session. You solve the blocker, and the agent continues from the same state.
Password handling resolves in this order:
- remote viewer
- user-supplied shell command
- ask-in-chat as a last resort
See docs/remote.md and docs/interruptions.md.
Most sites are simple. Some are not.
For signed requests, binary protocols, minified encoders, rotating IDs, and hidden request builders, klura exposes deeper tools to the agent.
Examples:
- find the request builder in bundled JavaScript
- set breakpoints when a request fires
- inspect signing functions from the live page
- locate WebSocket encoders
- compare binary payloads by structure instead of exact bytes
- classify failed probes as getting closer, stuck, or oscillating
Klura can handle even the toughest sites, and could even one-shot Facebook Messenger's binary MQTT /ls_req send path, regenerating rotating BigInt fields and replaying the frame through the page's authenticated socket in 2.365s.
The runtime does not brute-force endpoints, enumerate IDs outside the user's scope, or fuzz inputs.
See docs/reverse-engineering.md.
Klura is useful when the task is repetitive, browser-based, and not well-served by a public API.
Good fits:
- internal tools
- legacy admin panels
- SaaS products behind login
- web apps with private APIs but no public API
- repeated form submissions
- customer support workflows
- message sending
- issue creation
- CRM updates
- dashboard reads
- workflows that currently require brittle Playwright scripts
Bad fits:
- one-off tasks
- sites you are not authorized to use
- high-scale scraping
- endpoint or ID enumeration
- tasks that violate platform policy
- flows where the UI is intentionally the security boundary
- A scraping framework. Klura targets your own logged-in sessions, not unauthenticated pages at scale. If you're comparing it to Botasaurus, undetected-chromedriver, playwright-stealth, or Apify, that's a different category of tool.
- Code you write. Strategies are reverse-engineered from one observed browser run by the LLM driving the session. There's no Python or JS script for you to author or maintain.
- An anti-detect toolkit. Stealth fingerprint patches are supported; behavioral evasion (humanlike cursor jitter, residential proxies, CAPTCHA-solving services) isn't part of the mainline.
Klura depends on the model driving it.
Discovery quality varies by model; saved strategies replay deterministically.
Current snapshot:
| Model | Status |
|---|---|
GPT-5.6 Sol (gpt-5.6-sol) |
Very strong across ordinary and complex LIFTs |
| Sonnet 4.6 | Strong across ordinary and complex LIFTs |
| GLM 4.7 | Solid across most ordinary tasks |
Klura drives a real browser session you are already logged into and replays the same kinds of calls your own UI makes on your own account.
That is generally on the authorized side of unauthorized-access law.
Platform Terms of Service are separate.
Many major platforms restrict automation. Whether your usage triggers enforcement depends on the platform and how you use klura.
Practical guidance:
- read the policy of any site you automate
- stay within your own account and authorization scope
- avoid doing at scale what you would not reasonably do manually
- do not enumerate endpoints
- do not enumerate IDs outside your own scope
- do not fuzz inputs
- use klura's policy tools to cap strategy tiers per platform
See docs/policy.md, docs/trust.md, and docs/principles.md#stealth-not-bot-evasion.
Runtime settings live in:
~/.klura/config.json
You can edit the file directly or ask your agent to use klura's configuration tools:
describe_configconfigurerestart_runtime
A few knobs that are worth knowing about up front:
pool.driver(default unset → bundled Playwright driver) — switches the browser driver. Set to"@klura/driver-playwright-stealth"to enable stealth fingerprint patches (puppeteer-extra-plugin-stealth) for sites with stricter bot detection. BYO drivers can be installed by package name or absolute path.pool.connect(default off) — drive a normally-launched Chrome over CDP instead of letting Playwright launch it. A Chrome launched the ordinary way clears managed browser challenges that a Playwright-launched one loops on forever — the tell is the launch profile, not the CDP connection.{ "enabled": true, "mode": "spawn" }spawns a real Chrome with a persistent profile;"mode": "attach"connects to a Chrome you started with--remote-debugging-port. See docs/drivers.md#connect-mode.remote.auto_open("always" | "on_local" | "never", default"on_local") — when the remote viewer URL is reachable from the runtime host, klura spawns the OS URL handler so your default browser opens the viewer automatically. Skips the LLM-relay channel where long signed URLs tend to get a single byte garbled. Set to"never"for headless / SSH setups.remote.short_url(boolean, defaulttrue) — surface a short single-use redirect URL (≈16 chars, 60s TTL) to the agent instead of the full JWT URL. Survives chat-renderer rewrites where the long URL doesn't.
See docs/run-lifecycle.md#settings-reference-kluraconfigjson and REFERENCE.md#configure.
Start here:
- ARCHITECTURE.md — lifecycle, strategy tiers, secondary capabilities, and docs map
- REFERENCE.md — strategy schemas and agent-facing reference
- docs/discovery.md — how discovery works and what gets saved
- docs/reverse-engineering.md — deeper toolkit for signed, encoded, and binary requests
- docs/logbook.md — platform maps and persistent observations
- docs/run-lifecycle.md — daemon lifecycle and runtime settings
- docs/principles.md — design principles behind the runtime
- docs/policy.md — policy controls and safety boundaries
- docs/trust.md — trust model and operational guidance
- docs/remote.md — live viewer and human handoff
- docs/interruptions.md — CAPTCHA, 2FA, passwords, and blockers
Klura is new and moving fast. If the idea resonates:
- ⭐ Star the repo to follow along.
- 💬 Join the Discord — discovery walkthroughs, what's breaking, what's next.
- 🐛 Open an issue naming a site you wish your agent could just use. Real workflows drive what gets built.
- 🔧 Contribute a driver, transport, prerequisite method, or validation improvement — see Contributing.
The single most useful thing you can do: point klura at the most annoying internal tool you have, watch run 1 versus run 2, and tell us what broke.
Narek Mailian — freelance engineer.
Klura is a standalone project.
Commercial licensing, strategic partnerships, or integration conversations:
Before opening a PR, skim docs/principles.md.
Contributions that fit especially well:
- drivers
- pool backends
- listener transports
- prerequisite methods
- validation improvements
- focused test fixtures
- better docs for real workflows
Please avoid:
- endpoint probing
- ID enumeration outside the user's own scope
- mainline bot-evasion features
- platform-specific runtime heuristics
- brand names in agent-facing docs
Contributors sign the klura Individual Contributor License Agreement before a PR can be merged.
Full text: CLA.md.
Business Source License 1.1 with an Additional Use Grant.
The Licensed Work converts to the Apache License, Version 2.0 on the Change Date specified in LICENSE.
See LICENSE and NOTICE for the full terms.
You may copy, modify, and use the Licensed Work freely for non-production use.
Production use is permitted under the Additional Use Grant, except that you may not:
- offer the Licensed Work, in whole or in part, to third parties as a hosted or managed service;
- expose the Licensed Work's functionality to third parties via an API, SDK, or other interface;
- use the Licensed Work to build, offer, or operate a Competing Service; or
- sublicense, sell, or resell access to the Licensed Work or its functionality.
For a commercial license that lifts these restrictions, contact:
Footnotes
-
All rows used GPT-5.6 Sol (
gpt-5.6-sol) through Codex. ↩ -
Agent-reported after the raw Playwright run completes without a blocker. ↩
-
Klura cold time includes browsing, capture, triage, LIFT, validation, and saving the reusable strategy. It is the one-time learning cost. ↩
-
klura.execute()with no agent SDK in the loop; median of five sequential calls. A conversational host still spends tokens deciding to make the call. ↩
{ "agent": { "provider": "openai", "model": "gpt-5", "base_url": "https://api.openai.com/v1", "api_key": "sk-...", }, }