docs: homepage redesign, mermaid diagrams, cookbook screenshots, and Laminar observability (#5046)
|
|
@ -200,10 +200,12 @@ This uses 5 blocks across 3 categories: browser automation, data and extraction,
|
|||
|
||||
### What you built
|
||||
|
||||
```
|
||||
[find_hiring_thread] → [scrape_listings] → [process_each (loop)] → [send_digest]
|
||||
Browser Task Extraction └─ [summarize] Send Email
|
||||
Text Prompt
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["find_hiring_thread<br/>Browser Task"] --> B["scrape_listings<br/>Extraction"]
|
||||
B --> C["process_each<br/>Loop"]
|
||||
C --> D["summarize<br/>Text Prompt"]
|
||||
D --> E["send_digest<br/>Send Email"]
|
||||
```
|
||||
|
||||
Five blocks, three categories, zero code. You can now re-run this workflow anytime, tweak the extraction schema to pull different fields, swap the email for an HTTP Request to post to Slack, or add a Conditional block to only email when listings match certain criteria.
|
||||
|
|
|
|||
|
|
@ -27,6 +27,13 @@ Each cookbook walks through the workflow step-by-step, explaining design decisio
|
|||
>
|
||||
Search for jobs on any portal, extract listings, generate tailored answers with AI, and submit applications automatically.
|
||||
</Card>
|
||||
<Card
|
||||
title="Healthcare Portal Data Extraction"
|
||||
icon="hospital-user"
|
||||
href="/cookbooks/healthcare-portal-data"
|
||||
>
|
||||
Extract patient demographics and billing data from EHR portals like OpenEMR using residential proxies and browser profiles.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
---
|
||||
|
|
@ -46,7 +53,7 @@ All cookbooks require a Skyvern API key. Here's how to get one:
|
|||
</Frame>
|
||||
</Step>
|
||||
<Step title="Set your environment variable">
|
||||
Set the `SKYVERN_API_KEY` environment variable in your shell or `.env` file.
|
||||
Set the `SKYVERN_API_KEY` environment variable in your shell.
|
||||
```bash
|
||||
export SKYVERN_API_KEY="your-api-key"
|
||||
```
|
||||
|
|
|
|||
210
docs/debugging/observability-with-laminar.mdx
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
---
|
||||
title: Observability with Laminar
|
||||
subtitle: Add observability to your Skyvern automations with Laminar
|
||||
slug: debugging/observability-with-laminar
|
||||
---
|
||||
|
||||
[Laminar](https://www.lmnr.ai/) is an observability platform for AI applications. When integrated with Skyvern, it captures traces of your automation runs in Laminar's dashboard. What you see depends on how you're running Skyvern:
|
||||
|
||||
- **Skyvern Cloud (via SDK)** — Laminar wraps the `run_task` / `run_workflow` call, so you get a trace span around the API request and response: latency, status, errors, and the returned output.
|
||||
- **Self-hosted** — Skyvern's server can export full traces to Laminar, including every LLM call (prompts, responses, token usage), browser actions, and workflow step execution. See [self-hosted tracing setup](#self-hosted-tracing-setup) below.
|
||||
|
||||
<Tip>
|
||||
Laminar traces complement [artifacts](/debugging/using-artifacts). Use artifacts for per-run debugging (screenshots, recordings, logs) and Laminar for tracking patterns across runs — failure rates, response times, and which tasks are slowest.
|
||||
</Tip>
|
||||
|
||||
<Note>
|
||||
This guide is also available in the [Laminar documentation](https://docs.lmnr.ai/tracing/integrations/skyvern).
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Laminar integration requires a Skyvern SDK and the Laminar SDK:
|
||||
|
||||
<CodeGroup>
|
||||
```bash Python
|
||||
pip install skyvern 'lmnr[all]'
|
||||
```
|
||||
|
||||
```bash TypeScript
|
||||
npm install @skyvern/client @lmnr-ai/lmnr
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
You will also need:
|
||||
- A **Skyvern API key** — get one at [app.skyvern.com/settings](https://app.skyvern.com/settings/api-keys)
|
||||
- A **Laminar API key** — sign up at [lmnr.ai](https://www.lmnr.ai/) and create a project
|
||||
|
||||
---
|
||||
|
||||
## Set up environment variables
|
||||
|
||||
Add both keys to your `.env` file:
|
||||
|
||||
```bash .env
|
||||
SKYVERN_API_KEY=your-skyvern-api-key
|
||||
LMNR_PROJECT_API_KEY=your-laminar-api-key
|
||||
```
|
||||
|
||||
<Frame>
|
||||
<video
|
||||
autoPlay
|
||||
controls
|
||||
muted
|
||||
playsInline
|
||||
className="w-full aspect-video rounded-xl"
|
||||
src="/images/laminar-keys.mp4"
|
||||
></video>
|
||||
</Frame>
|
||||
|
||||
---
|
||||
|
||||
## Run a traced task
|
||||
|
||||
This example scrapes the top 3 posts from Hacker News with Laminar tracing enabled. Call `Laminar.initialize()` before any Skyvern calls — it reads `LMNR_PROJECT_API_KEY` from your environment automatically.
|
||||
|
||||
<CodeGroup>
|
||||
```python Python
|
||||
import os
|
||||
import asyncio
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
from lmnr import Laminar
|
||||
Laminar.initialize()
|
||||
|
||||
from skyvern import Skyvern
|
||||
|
||||
client = Skyvern(api_key=os.getenv("SKYVERN_API_KEY"))
|
||||
|
||||
async def main():
|
||||
result = await client.run_task(
|
||||
prompt="Get the title and URL of the top 3 posts on Hacker News.",
|
||||
url="https://news.ycombinator.com",
|
||||
wait_for_completion=True,
|
||||
)
|
||||
print(f"Status: {result.status}")
|
||||
print(f"Output: {result.output}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
```typescript TypeScript
|
||||
import { Laminar } from "@lmnr-ai/lmnr";
|
||||
Laminar.initialize();
|
||||
|
||||
import { Skyvern } from "@skyvern/client";
|
||||
|
||||
const client = new Skyvern({
|
||||
apiKey: process.env.SKYVERN_API_KEY,
|
||||
});
|
||||
|
||||
async function main() {
|
||||
const result = await client.runTask({
|
||||
body: {
|
||||
prompt: "Get the title and URL of the top 3 posts on Hacker News.",
|
||||
url: "https://news.ycombinator.com",
|
||||
},
|
||||
waitForCompletion: true,
|
||||
});
|
||||
console.log(`Status: ${result.status}`);
|
||||
console.log(`Output: ${JSON.stringify(result.output, null, 2)}`);
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
Expected output:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "completed",
|
||||
"output": {
|
||||
"posts": [
|
||||
{"title": "Zig – Type Resolution Redesign and Language Changes", "url": "https://ziglang.org/devlog/2026/..."},
|
||||
{"title": "Create value for others and don't worry about the returns", "url": "https://geohot.github.io/..."},
|
||||
{"title": "U+237C ⍼ Is Azimuth", "url": "https://ionathan.ch/2026/02/16/angzarr.html"}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The task runs, the output is returned, and the full trace — every HTTP call, timing, and payload — appears in your Laminar dashboard.
|
||||
|
||||
<Note>
|
||||
**Python only:** You will see a `ForgeApp is not initialized` error in stderr on startup. This is harmless — `lmnr[all]` tries to instrument Skyvern's server-side internals, which aren't present when using the client SDK. Your traces still work correctly.
|
||||
</Note>
|
||||
|
||||
<Warning>
|
||||
**Python only:** `LaminarLiteLLMCallback` is deprecated and unnecessary. Laminar instruments LiteLLM directly — no callback setup is needed.
|
||||
</Warning>
|
||||
|
||||
---
|
||||
|
||||
## What traces capture
|
||||
|
||||
What shows up in Laminar depends on your setup.
|
||||
|
||||
### Skyvern Cloud (via SDK)
|
||||
|
||||
When calling `run_task` or `run_workflow` through the SDK, Laminar traces the client-side call:
|
||||
|
||||
| Trace data | What it shows |
|
||||
|------------|---------------|
|
||||
| API request/response | The full round-trip to Skyvern's API — status, latency, payload size |
|
||||
| Task output | The extracted data or completion result |
|
||||
| Errors | HTTP errors, timeouts, and task failures |
|
||||
|
||||
This is useful for monitoring how your application interacts with Skyvern — tracking which tasks fail, how long they take, and what outputs you're getting back.
|
||||
|
||||
### Self-hosted
|
||||
|
||||
When running Skyvern on your own infrastructure, you get deep server-side traces by configuring Laminar in Skyvern's environment. This gives you visibility into everything happening inside the agent:
|
||||
|
||||
| Trace data | What it shows |
|
||||
|------------|---------------|
|
||||
| LLM interactions | Every prompt sent to the model and its response, including token counts |
|
||||
| Browser actions | Each click, type, and navigation the agent performed |
|
||||
| Workflow steps | Sequential block execution and data passed between blocks |
|
||||
| Image tracing | Screenshots sent to the LLM for analysis |
|
||||
| Performance metrics | Latency and cost per LLM call |
|
||||
| Errors | Exceptions at any layer — LLM, browser, workflow engine |
|
||||
|
||||
---
|
||||
|
||||
## Self-hosted tracing setup
|
||||
|
||||
If you're running Skyvern on your own infrastructure, add these to your server's environment:
|
||||
|
||||
```bash .env
|
||||
LMNR_PROJECT_API_KEY=your-laminar-api-key
|
||||
```
|
||||
|
||||
Skyvern's server includes a built-in `LaminarTrace` integration that initializes Laminar with the LiteLLM callback, capturing every LLM call, token count, and cost. It disables the automatic Skyvern/Patchright instrumentors (to avoid conflicts) and uses Laminar's `@observe` decorator on internal methods instead.
|
||||
|
||||
No code changes needed — once the env var is set, traces appear in your Laminar project automatically.
|
||||
|
||||
---
|
||||
|
||||
## Next steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="Using Artifacts"
|
||||
icon="file-lines"
|
||||
href="/debugging/using-artifacts"
|
||||
>
|
||||
Per-run recordings, screenshots, logs, and network data
|
||||
</Card>
|
||||
<Card
|
||||
title="Troubleshooting Guide"
|
||||
icon="wrench"
|
||||
href="/debugging/troubleshooting-guide"
|
||||
>
|
||||
Common issues and how to fix them
|
||||
</Card>
|
||||
</CardGroup>
|
||||
184
docs/docs.json
|
|
@ -1,26 +1,53 @@
|
|||
{
|
||||
"$schema": "https://mintlify.com/docs.json",
|
||||
"theme": "mint",
|
||||
"theme": "palm",
|
||||
"name": "Skyvern",
|
||||
"colors": {
|
||||
"primary": "#6366F1",
|
||||
"light": "#818CF8",
|
||||
"dark": "#4F46E5"
|
||||
"primary": "#4A6CF7",
|
||||
"light": "#7B93FA",
|
||||
"dark": "#1B2559"
|
||||
},
|
||||
"appearance": {
|
||||
"default": "light"
|
||||
},
|
||||
"background": {
|
||||
"color": {
|
||||
"light": "#F8F5EF",
|
||||
"dark": "#1C1917"
|
||||
}
|
||||
},
|
||||
"fonts": {
|
||||
"heading": {
|
||||
"family": "Inter",
|
||||
"weight": 600
|
||||
},
|
||||
"body": {
|
||||
"family": "Inter",
|
||||
"weight": 400
|
||||
}
|
||||
},
|
||||
"logo": {
|
||||
"light": "/logo/light.svg",
|
||||
"dark": "/logo/dark.svg",
|
||||
"light": "/logo/light.png",
|
||||
"dark": "/logo/dark.png",
|
||||
"href": "https://skyvern.com"
|
||||
},
|
||||
"favicon": "/favicon.svg",
|
||||
"favicon": "/favicon.png",
|
||||
"search": {
|
||||
"prompt": "Search Skyvern docs..."
|
||||
},
|
||||
"navigation": {
|
||||
"tabs": [
|
||||
{
|
||||
"tab": "Home",
|
||||
"pages": ["index"]
|
||||
},
|
||||
{
|
||||
"tab": "Documentation",
|
||||
"groups": [
|
||||
{
|
||||
"group": "Getting Started",
|
||||
"pages": [
|
||||
"getting-started/introduction",
|
||||
"getting-started/quickstart",
|
||||
"getting-started/core-concepts"
|
||||
]
|
||||
|
|
@ -46,7 +73,6 @@
|
|||
"group": "Optimization",
|
||||
"pages": [
|
||||
"optimization/browser-sessions",
|
||||
"optimization/browser-tunneling",
|
||||
"optimization/browser-profiles",
|
||||
"optimization/cost-control"
|
||||
]
|
||||
|
|
@ -68,6 +94,7 @@
|
|||
"pages": [
|
||||
"debugging/using-artifacts",
|
||||
"debugging/troubleshooting-guide",
|
||||
"debugging/observability-with-laminar",
|
||||
"debugging/faq"
|
||||
]
|
||||
},
|
||||
|
|
@ -191,9 +218,7 @@
|
|||
},
|
||||
{
|
||||
"tab": "Changelog",
|
||||
"pages": [
|
||||
"changelog"
|
||||
]
|
||||
"pages": ["changelog"]
|
||||
},
|
||||
{
|
||||
"tab": "API Reference",
|
||||
|
|
@ -221,6 +246,7 @@
|
|||
"twitter": "https://twitter.com/skyvernai"
|
||||
}
|
||||
},
|
||||
"css": "/style.css",
|
||||
"api": {
|
||||
"baseUrl": "https://api.skyvern.com",
|
||||
"auth": {
|
||||
|
|
@ -230,5 +256,139 @@
|
|||
"playground": {
|
||||
"display": "interactive"
|
||||
}
|
||||
}
|
||||
},
|
||||
"redirects": [
|
||||
{
|
||||
"source": "/introduction",
|
||||
"destination": "/getting-started/quickstart"
|
||||
},
|
||||
{
|
||||
"source": "/getting-started/skyvern-in-action",
|
||||
"destination": "/getting-started/core-concepts"
|
||||
},
|
||||
{
|
||||
"source": "/getting-started/prompting-guide",
|
||||
"destination": "/debugging/troubleshooting-guide"
|
||||
},
|
||||
{
|
||||
"source": "/running-tasks/run-tasks",
|
||||
"destination": "/running-automations/run-a-task"
|
||||
},
|
||||
{
|
||||
"source": "/running-tasks/visualizing-results",
|
||||
"destination": "/debugging/using-artifacts"
|
||||
},
|
||||
{
|
||||
"source": "/running-tasks/cancel-runs",
|
||||
"destination": "/running-automations/run-a-task"
|
||||
},
|
||||
{
|
||||
"source": "/running-tasks/webhooks-faq",
|
||||
"destination": "/going-to-production/webhooks"
|
||||
},
|
||||
{
|
||||
"source": "/running-tasks/connect-local-browser",
|
||||
"destination": "/self-hosted/browser"
|
||||
},
|
||||
{
|
||||
"source": "/running-tasks/proxy-location",
|
||||
"destination": "/going-to-production/proxy-geolocation"
|
||||
},
|
||||
{
|
||||
"source": "/running-tasks/advanced-features",
|
||||
"destination": "/running-automations/task-parameters"
|
||||
},
|
||||
{
|
||||
"source": "/running-tasks/api-spec",
|
||||
"destination": "/running-automations/run-a-task"
|
||||
},
|
||||
{
|
||||
"source": "/workflows/manage-workflows",
|
||||
"destination": "/cloud/building-workflows/manage-workflows"
|
||||
},
|
||||
{
|
||||
"source": "/workflows/workflow-blocks-details",
|
||||
"destination": "/multi-step-automations/workflow-blocks-reference"
|
||||
},
|
||||
{
|
||||
"source": "/workflows/workflow-parameters",
|
||||
"destination": "/multi-step-automations/workflow-parameters"
|
||||
},
|
||||
{
|
||||
"source": "/workflows/run-workflows",
|
||||
"destination": "/cloud/building-workflows/run-a-workflow"
|
||||
},
|
||||
{
|
||||
"source": "/workflows/consistent-workflows",
|
||||
"destination": "/going-to-production/reliability-tips"
|
||||
},
|
||||
{
|
||||
"source": "/workflows/running-workflows",
|
||||
"destination": "/cloud/building-workflows/run-a-workflow"
|
||||
},
|
||||
{
|
||||
"source": "/workflows/introduction",
|
||||
"destination": "/multi-step-automations/build-a-workflow"
|
||||
},
|
||||
{
|
||||
"source": "/workflows/workflow-blocks",
|
||||
"destination": "/multi-step-automations/workflow-blocks-reference"
|
||||
},
|
||||
{
|
||||
"source": "/workflows/creating-workflows",
|
||||
"destination": "/multi-step-automations/build-a-workflow"
|
||||
},
|
||||
{
|
||||
"source": "/workflows/getting-workflows",
|
||||
"destination": "/multi-step-automations/build-a-workflow#step-7:-get-results"
|
||||
},
|
||||
{
|
||||
"source": "/workflows/what-is-a-parameter",
|
||||
"destination": "/multi-step-automations/workflow-parameters"
|
||||
},
|
||||
{
|
||||
"source": "/credentials/introduction",
|
||||
"destination": "/cloud/managing-credentials/credentials-overview"
|
||||
},
|
||||
{
|
||||
"source": "/credentials/passwords",
|
||||
"destination": "/cloud/managing-credentials/password-credentials"
|
||||
},
|
||||
{
|
||||
"source": "/credentials/credit-cards",
|
||||
"destination": "/cloud/managing-credentials/credit-card-credentials"
|
||||
},
|
||||
{
|
||||
"source": "/credentials/totp",
|
||||
"destination": "/cloud/managing-credentials/totp-setup"
|
||||
},
|
||||
{
|
||||
"source": "/credentials/bitwarden",
|
||||
"destination": "/cloud/managing-credentials/external-providers"
|
||||
},
|
||||
{
|
||||
"source": "/credentials/custom-credential-service",
|
||||
"destination": "/cloud/managing-credentials/external-providers"
|
||||
},
|
||||
{
|
||||
"source": "/browser-sessions/introduction",
|
||||
"destination": "/optimization/browser-sessions"
|
||||
},
|
||||
{
|
||||
"source": "/browser-sessions/browser-profiles",
|
||||
"destination": "/optimization/browser-profiles"
|
||||
},
|
||||
{
|
||||
"source": "/observability/overview",
|
||||
"destination": "/debugging/using-artifacts"
|
||||
},
|
||||
{
|
||||
"source": "/integrations/make.com",
|
||||
"destination": "/integrations/make"
|
||||
},
|
||||
{
|
||||
"source": "/integrations/ollama-litellm",
|
||||
"destination": "/integrations/local-llms"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
BIN
docs/favicon.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
|
|
@ -56,18 +56,23 @@ When you need reusable, multi-step automations, use **Workflows** instead.
|
|||
|
||||
A **Workflow** is a reusable template composed of blocks. Unlike tasks, workflows can be versioned, shared across your team, and executed repeatedly with different parameters.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["Navigate<br/>Block"] --> B["Login<br/>Block"]
|
||||
B --> C["Extract<br/>Block"]
|
||||
C --> D["Download<br/>Block"]
|
||||
|
||||
subgraph WORKFLOW
|
||||
direction LR
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
end
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ WORKFLOW │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ Navigate │ → │ Login │ → │ Extract │ → │ Download │ │
|
||||
│ │ Block │ │ Block │ │ Block │ │ Block │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
||||
│ │
|
||||
│ Parameters: {{search_query}}, {{max_price}} │
|
||||
│ Each block can reference outputs from previous blocks │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
> **Parameters:** `{{search_query}}`, `{{max_price}}`
|
||||
> Each block can reference outputs from previous blocks.
|
||||
|
||||
```python
|
||||
result = await skyvern.run_workflow(
|
||||
|
|
@ -141,16 +146,14 @@ For detailed block configuration, see [Workflow Blocks](/workflows/workflow-bloc
|
|||
|
||||
Every time you execute a task or workflow, Skyvern creates a **Run** to track progress and store outputs.
|
||||
|
||||
```
|
||||
┌→ completed
|
||||
│
|
||||
├→ failed
|
||||
│
|
||||
created → queued → running ─┼→ timed_out
|
||||
│
|
||||
├→ terminated
|
||||
│
|
||||
└→ canceled
|
||||
```mermaid
|
||||
flowchart LR
|
||||
created --> queued --> running
|
||||
running --> completed
|
||||
running --> failed
|
||||
running --> timed_out
|
||||
running --> terminated
|
||||
running --> canceled
|
||||
```
|
||||
|
||||
```python
|
||||
|
|
@ -191,29 +194,12 @@ print(result.output) # {"heading": "Welcome"}
|
|||
|
||||
Credentials provide secure storage for authentication data. Skyvern encrypts credentials at rest and in transit, and injects them directly into the browser—**credentials are never sent to or seen by the LLM**.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ SECURITY MODEL │
|
||||
│ │
|
||||
│ You store credentials Skyvern encrypts & stores │
|
||||
│ │ │ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌─────────────┐ ┌─────────────────┐ │
|
||||
│ │ Skyvern UI │ │ Encrypted Vault │ │
|
||||
│ │ or API │ ─────────── │ (or Bitwarden, │ │
|
||||
│ └─────────────┘ │ 1Password) │ │
|
||||
│ └────────┬────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────┐ │
|
||||
│ │ Login Block │ │
|
||||
│ │ injects into │ │
|
||||
│ │ browser fields │ │
|
||||
│ └─────────────────┘ │
|
||||
│ │ │
|
||||
│ LLM sees: "login happened" │
|
||||
│ LLM never sees: actual credentials │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["You store credentials"] --> B["Skyvern UI<br/>or API"]
|
||||
B --> C["Encrypted Vault<br/>(or Bitwarden, 1Password)"]
|
||||
C --> D["Login Block<br/>injects into<br/>browser fields"]
|
||||
D --> E["LLM sees: 'login happened'<br/>LLM never sees: actual credentials"]
|
||||
```
|
||||
|
||||
**Supported credential types:**
|
||||
|
|
@ -235,24 +221,23 @@ See [Credentials](/sdk-reference/credentials) for setup instructions.
|
|||
|
||||
Skyvern offers two ways to manage browser state across runs:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph SESSION ["Browser Session (live, temporary)"]
|
||||
A["Active Browser<br/>Instance"]
|
||||
end
|
||||
subgraph PROFILE ["Browser Profile (saved, reusable)"]
|
||||
B["Snapshot of state<br/>(cookies, storage)"]
|
||||
end
|
||||
A -- "save" --> B
|
||||
B -- "restore" --> A
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ BROWSER SESSION BROWSER PROFILE │
|
||||
│ (live, temporary) (saved, reusable) │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ Active │ ──save──▶ │ Snapshot │ │
|
||||
│ │ Browser │ │ of state │ │
|
||||
│ │ Instance │ ◀──restore── │ (cookies, │ │
|
||||
│ └─────────────┘ │ storage) │ │
|
||||
│ └─────────────┘ │
|
||||
│ • Expires after timeout • Persists indefinitely │
|
||||
│ • For real-time chaining • For skipping login │
|
||||
│ • Max 24 hours • Shared across team │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
| | Browser Session | Browser Profile |
|
||||
|---|---|---|
|
||||
| **Lifetime** | Expires after timeout (max 24h) | Persists indefinitely |
|
||||
| **Use case** | Real-time task chaining | Skip login on repeated runs |
|
||||
| **Sharing** | Single use | Shared across team |
|
||||
|
||||
### Browser Sessions
|
||||
|
||||
|
|
|
|||
76
docs/getting-started/introduction.mdx
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
---
|
||||
title: What is Skyvern?
|
||||
subtitle: AI-powered browser automation for any website
|
||||
slug: getting-started/introduction
|
||||
---
|
||||
|
||||
Skyvern automates anything you can do in a browser. You describe what you want in plain English, and Skyvern opens a real Chromium browser, looks at the page, and completes the task. No CSS selectors, no scripts, no maintenance when the site changes.
|
||||
|
||||
The reason this works is that Skyvern doesn't rely on hardcoded element paths. It screenshots the page, reads the DOM, and uses an LLM to decide what to do next, the same way a person would look at a screen and figure out where to click. That means it works on sites it's never seen before, and it keeps working when those sites redesign.
|
||||
|
||||
---
|
||||
|
||||
## The agent loop
|
||||
|
||||
Every Skyvern automation, whether you trigger it from the dashboard, the API, or a Zapier workflow, runs the same loop:
|
||||
|
||||
<img src="/images/skyvern-agent-loop.png" alt="Skyvern agent loop: Screenshot → Extract DOM → LLM reasons → Execute action → Goal check → Repeat" />
|
||||
|
||||
Each cycle through this loop is called a **step**. Understanding what happens in each step helps you write better prompts and debug runs when something goes wrong.
|
||||
|
||||
1. **Screenshot the viewport.** Skyvern captures what's currently on screen, giving the LLM visual context: where buttons are, what forms look like, whether a modal is blocking the page.
|
||||
2. **Extract the DOM.** The visible page is scraped into a simplified tree of interactive elements (inputs, buttons, links, dropdowns) with their labels and positions. The LLM uses both the screenshot and the DOM together: the image shows layout and visual context, the DOM provides precise element identifiers that Playwright can target.
|
||||
3. **LLM decides the next action.** The screenshot, DOM tree, and your original prompt go to the LLM. It picks which element to interact with and what to do: click, type, select, scroll, upload. If there's data to extract, it pulls that too.
|
||||
4. **Playwright executes.** The action runs in a real Chromium browser. If credentials are needed, they're injected directly into the browser at this point. The LLM never sees passwords, TOTP codes, or credit card numbers.
|
||||
5. **Check if the goal is met.** If not, loop back to step 1 and screenshot the now-changed page. If yes, return the results.
|
||||
|
||||
A typical task takes 2 to 10 steps. You can set `max_steps` to cap cost during development.
|
||||
|
||||
### The Planner-Agent-Validator system
|
||||
|
||||
For anything beyond simple single-page tasks, Skyvern 2.0 wraps the agent loop in a higher-level system with three components:
|
||||
|
||||
<img src="/images/skyvern-system-architecture.png" alt="Skyvern 2.0 architecture: Planner breaks prompt into sub-tasks, Task Agent executes them, Validator confirms completion" />
|
||||
|
||||
The **Planner** takes your prompt and breaks it into an ordered sequence of sub-tasks. If you say "log into the vendor portal, download all invoices from January, and save them as PDFs," the Planner sequences that into: navigate to login → authenticate → find the invoice section → loop through January invoices → download each one.
|
||||
|
||||
The **Task Agent** picks up each sub-task and runs the agent loop described above. It's focused on one thing at a time, which makes it more reliable than trying to handle a complex multi-page flow in a single pass.
|
||||
|
||||
The **Validator** checks whether the overall goal was actually met after the Task Agent finishes. If the Validator determines something was missed or went wrong, it sends feedback back to the Planner, which can re-sequence or retry. This closed-loop feedback is what makes Skyvern reliable on complex workflows where a single missed step would break the whole thing.
|
||||
|
||||
---
|
||||
|
||||
## What Skyvern handles for you
|
||||
|
||||
Most browser automation breaks down at authentication, CAPTCHAs, or dynamic content. Skyvern handles these natively so you don't have to build workarounds.
|
||||
|
||||
**Authentication and credentials.** You store passwords, TOTP secrets, and credit card numbers through the Credentials API or the dashboard. They're encrypted at rest and injected directly into browser fields during execution. The LLM orchestrates the login flow (finds the form, clicks submit, handles 2FA prompts) but never sees the actual credential values. Supports Bitwarden, 1Password, and Azure Key Vault as external sources.
|
||||
|
||||
**CAPTCHAs.** Automatically detected and solved during execution. You don't configure anything.
|
||||
|
||||
**Structured data extraction.** You can pass a JSON Schema defining exactly what fields you want, and Skyvern extracts typed data that conforms to it. Or you can skip the schema and let Skyvern infer structure from your prompt.
|
||||
|
||||
**File operations.** Download files from websites, upload documents to form fields, parse PDFs, CSVs, and Excel files. Downloaded files come back as signed URLs with checksums.
|
||||
|
||||
**Proxy and geolocation.** Residential proxies route through real IPs in 30+ countries. Set `proxy_location` per task when you need to appear from a specific region.
|
||||
|
||||
**Browser state persistence.** Sessions keep a live browser open across multiple tasks for up to 24 hours, useful when you need to chain tasks that share login state. Profiles snapshot cookies, auth tokens, and local storage into a reusable package you can restore on future runs, so you don't re-authenticate every time.
|
||||
|
||||
**Multi-step workflows.** When a single task isn't enough, Workflows let you chain blocks together: navigate, login, loop through a list, extract data, branch on conditions, send emails. Workflows are parameterized and version-controlled. You can build them visually in the dashboard or define them through the API.
|
||||
|
||||
---
|
||||
|
||||
## Get started
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Automate from the dashboard" icon="window-maximize" href="/cloud/getting-started/overview">
|
||||
Type what you want, watch it happen live, get results back. Build multi-step workflows with the visual editor. Connect to Zapier, Make, or n8n. No code required.
|
||||
</Card>
|
||||
<Card title="Integrate via API or SDK" icon="code" href="/getting-started/quickstart">
|
||||
Install the Python or TypeScript SDK, get an API key, and run your first automation in 5 minutes.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Card title="Deploy on your own infrastructure" icon="server" href="/self-hosted/overview">
|
||||
Skyvern is open-source. Run it with Docker, connect your own LLM keys, and keep all data on your network.
|
||||
</Card>
|
||||
BIN
docs/images/cookbooks/add-block.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
docs/images/cookbooks/add-params.png
Normal file
|
After Width: | Height: | Size: 1 MiB |
BIN
docs/images/cookbooks/create-workflow.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
docs/images/cookbooks/credentials.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
docs/images/cookbooks/creds-id-copy.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
docs/images/cookbooks/ember--roasters.png
Normal file
|
After Width: | Height: | Size: 966 KiB |
BIN
docs/images/cookbooks/er-creds.png
Normal file
|
After Width: | Height: | Size: 1 MiB |
BIN
docs/images/cookbooks/job-stash.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
docs/images/cookbooks/js-creds.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
docs/images/laminar-keys.mp4
Normal file
BIN
docs/images/skyvern-agent-loop.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
docs/images/skyvern-system-architecture.png
Normal file
|
After Width: | Height: | Size: 145 KiB |
151
docs/index.mdx
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
---
|
||||
title: Skyvern Documentation
|
||||
slug: /
|
||||
mode: custom
|
||||
---
|
||||
|
||||
<div className="sk-page">
|
||||
|
||||
{/* ===== HERO ===== */}
|
||||
|
||||
<div className="sk-hero">
|
||||
<div className="sk-hero-inner">
|
||||
<div className="sk-hero-left">
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "12px", marginBottom: "12px" }}>
|
||||
<p className="sk-mono sk-label" style={{ margin: "0" }}>DOCUMENTATION</p>
|
||||
<a href="/changelog" className="sk-version-badge">v1.0.22 — latest</a>
|
||||
</div>
|
||||
<h1 className="sk-hero-title">
|
||||
Automate any<br />browser workflow<br /><span className="sk-hero-accent">with AI.</span>
|
||||
</h1>
|
||||
<p className="sk-hero-sub">
|
||||
Describe what you want in plain English. Skyvern opens a real browser, reads the page visually, and completes the task.
|
||||
</p>
|
||||
<div className="sk-hero-actions">
|
||||
<a href="/getting-started/quickstart" className="sk-btn-primary">Get started with the API →</a>
|
||||
<a href="/cloud/getting-started/overview" className="sk-btn-secondary">Use the dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="sk-hero-right">
|
||||
<div className="sk-terminal">
|
||||
<div className="sk-terminal-bar">
|
||||
<span className="sk-dot sk-dot-red"></span>
|
||||
<span className="sk-dot sk-dot-yellow"></span>
|
||||
<span className="sk-dot sk-dot-green"></span>
|
||||
<span className="sk-terminal-title">skyvern.log</span>
|
||||
</div>
|
||||
<div className="sk-terminal-body">
|
||||
<p className="sk-mono">> Initializing browser session...</p>
|
||||
<p className="sk-mono sk-t-teal">> Navigating to target URL... [OK]</p>
|
||||
<p className="sk-mono sk-t-teal">> Analyzing page with vision... [OK]</p>
|
||||
<p className="sk-mono">> Planning actions...</p>
|
||||
<p className="sk-mono sk-t-orange">→ ACTIONS_PLANNED: 4</p>
|
||||
<p className="sk-mono">> Executing: fill_form</p>
|
||||
<p className="sk-mono">> Executing: click_submit</p>
|
||||
<p className="sk-mono sk-t-teal">> Task completed successfully</p>
|
||||
<p className="sk-mono sk-t-muted">→ DURATION: 3.2s</p>
|
||||
<p className="sk-mono">> READY<span className="sk-cursor">▊</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ===== BENTO GRID — 3 PERSONA LANES ===== */}
|
||||
|
||||
<div className="sk-bento-row sk-bento-3col">
|
||||
<div className="sk-bento-cell">
|
||||
<p className="sk-mono sk-label">01 — NO CODE</p>
|
||||
<h3 className="sk-cell-title">Automate without code</h3>
|
||||
<p className="sk-cell-desc">Use the dashboard to run tasks and build workflows visually.</p>
|
||||
<div className="sk-cell-links">
|
||||
<a href="/cloud/getting-started/overview" className="sk-cell-link">Dashboard overview <span className="sk-arrow">↗</span></a>
|
||||
<a href="/cloud/getting-started/run-your-first-task" className="sk-cell-link">Run your first task <span className="sk-arrow">↗</span></a>
|
||||
<a href="/cloud/building-workflows/build-a-workflow" className="sk-cell-link">Build a workflow <span className="sk-arrow">↗</span></a>
|
||||
<a href="/integrations/zapier" className="sk-cell-link">Connect to Zapier <span className="sk-arrow">↗</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="sk-bento-cell">
|
||||
<p className="sk-mono sk-label">02 — API</p>
|
||||
<h3 className="sk-cell-title">Build with the API</h3>
|
||||
<p className="sk-cell-desc">Integrate browser automation into your product with Python, TypeScript, or REST.</p>
|
||||
<div className="sk-cell-links">
|
||||
<a href="/getting-started/quickstart" className="sk-cell-link">API quickstart <span className="sk-arrow">↗</span></a>
|
||||
<a href="/sdk-reference/overview" className="sk-cell-link">Python SDK <span className="sk-arrow">↗</span></a>
|
||||
<a href="/ts-sdk-reference/overview" className="sk-cell-link">TypeScript SDK <span className="sk-arrow">↗</span></a>
|
||||
<a href="/api-reference" className="sk-cell-link">API reference <span className="sk-arrow">↗</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="sk-bento-cell">
|
||||
<p className="sk-mono sk-label">03 — SELF-HOST</p>
|
||||
<h3 className="sk-cell-title">Self-host</h3>
|
||||
<p className="sk-cell-desc">Run Skyvern on your own infrastructure with your own LLM keys.</p>
|
||||
<div className="sk-cell-links">
|
||||
<a href="/self-hosted/overview" className="sk-cell-link">Deployment overview <span className="sk-arrow">↗</span></a>
|
||||
<a href="/self-hosted/docker" className="sk-cell-link">Docker setup <span className="sk-arrow">↗</span></a>
|
||||
<a href="/self-hosted/llm-configuration" className="sk-cell-link">LLM configuration <span className="sk-arrow">↗</span></a>
|
||||
<a href="/self-hosted/kubernetes" className="sk-cell-link">Kubernetes <span className="sk-arrow">↗</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ===== BENTO GRID — 2 COL: HOW IT WORKS + CONCEPTS ===== */}
|
||||
|
||||
<div className="sk-bento-row sk-bento-2col">
|
||||
<a href="/getting-started/introduction" className="sk-bento-cell sk-bento-cell-link">
|
||||
<p className="sk-mono sk-label">ARCHITECTURE</p>
|
||||
<h3 className="sk-cell-title">How Skyvern works</h3>
|
||||
<p className="sk-cell-desc">The agent loop, Planner-Agent-Validator architecture, and what happens under the hood when you run a task.</p>
|
||||
<span className="sk-mono sk-arrow-lg">↗</span>
|
||||
</a>
|
||||
<a href="/getting-started/core-concepts" className="sk-bento-cell sk-bento-cell-link">
|
||||
<p className="sk-mono sk-label">REFERENCE</p>
|
||||
<h3 className="sk-cell-title">Core concepts</h3>
|
||||
<p className="sk-cell-desc">Tasks, workflows, blocks, runs, credentials, browser sessions, and engines.</p>
|
||||
<span className="sk-mono sk-arrow-lg">↗</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* ===== BENTO GRID — 4 COL: USE CASES ===== */}
|
||||
|
||||
<p className="sk-mono sk-label" style={{ marginBottom: "24px", marginTop: "32px" }}>USE CASES</p>
|
||||
|
||||
<div className="sk-bento-row sk-bento-4col">
|
||||
<a href="/cookbooks/bulk-invoice-downloader" className="sk-bento-cell sk-bento-cell-link sk-bento-cell-sm sk-usecase-teal">
|
||||
<h4 className="sk-cell-title-sm">Download invoices</h4>
|
||||
<p className="sk-cell-desc-sm">Log into vendor portals, find invoices, download PDFs.</p>
|
||||
<span className="sk-mono sk-arrow-sm">↗</span>
|
||||
</a>
|
||||
<a href="/cookbooks/job-application-filler" className="sk-bento-cell sk-bento-cell-link sk-bento-cell-sm sk-usecase-orange">
|
||||
<h4 className="sk-cell-title-sm">Fill forms at scale</h4>
|
||||
<p className="sk-cell-desc-sm">Submit applications, registrations, and compliance forms.</p>
|
||||
<span className="sk-mono sk-arrow-sm">↗</span>
|
||||
</a>
|
||||
<a href="/running-automations/extract-structured-data" className="sk-bento-cell sk-bento-cell-link sk-bento-cell-sm sk-usecase-teal">
|
||||
<h4 className="sk-cell-title-sm">Extract data</h4>
|
||||
<p className="sk-cell-desc-sm">Pull structured data from any site without an API.</p>
|
||||
<span className="sk-mono sk-arrow-sm">↗</span>
|
||||
</a>
|
||||
<a href="/cookbooks/healthcare-portal-data" className="sk-bento-cell sk-bento-cell-link sk-bento-cell-sm sk-usecase-orange">
|
||||
<h4 className="sk-cell-title-sm">Healthcare portals</h4>
|
||||
<p className="sk-cell-desc-sm">Extract patient demographics and billing from EHR portals.</p>
|
||||
<span className="sk-mono sk-arrow-sm">↗</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* ===== FOOTER CTA ===== */}
|
||||
|
||||
<div className="sk-footer-cta">
|
||||
<div className="sk-footer-cta-inner">
|
||||
<p className="sk-footer-cta-text">
|
||||
<span className="sk-mono" style={{ color: "var(--sk-blue)", marginRight: "8px" }}>●</span>
|
||||
Open source · 20.8k+ GitHub stars
|
||||
</p>
|
||||
<div className="sk-footer-cta-links">
|
||||
<a href="https://github.com/Skyvern-AI/skyvern" className="sk-footer-link">GitHub ↗</a>
|
||||
<a href="https://discord.gg/skyvern" className="sk-footer-link">Discord ↗</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
BIN
docs/logo/dark.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
docs/logo/light.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
108
docs/snippets/homepage-hero.jsx
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
export const HomepageHero = () => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
padding: "48px 0 40px 0",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
gap: "8px",
|
||||
padding: "6px 16px",
|
||||
borderRadius: "20px",
|
||||
backgroundColor: "rgba(91, 138, 140, 0.08)",
|
||||
border: "1px solid rgba(91, 138, 140, 0.2)",
|
||||
fontSize: "13px",
|
||||
color: "#5B8A8C",
|
||||
marginBottom: "24px",
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
Open source on GitHub
|
||||
</div>
|
||||
<h1
|
||||
style={{
|
||||
fontSize: "42px",
|
||||
fontWeight: 700,
|
||||
lineHeight: 1.15,
|
||||
color: "#1a1a1a",
|
||||
margin: "0 0 16px 0",
|
||||
letterSpacing: "-0.02em",
|
||||
}}
|
||||
>
|
||||
Automate any browser workflow with AI
|
||||
</h1>
|
||||
<p
|
||||
style={{
|
||||
fontSize: "18px",
|
||||
lineHeight: 1.6,
|
||||
color: "#6B6560",
|
||||
maxWidth: "600px",
|
||||
margin: "0 auto 32px auto",
|
||||
}}
|
||||
>
|
||||
Describe what you want in plain English. Skyvern opens a real browser,
|
||||
reads the page visually, and completes the task.
|
||||
</p>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: "12px",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
}}
|
||||
>
|
||||
<a
|
||||
href="/getting-started/quickstart"
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
gap: "6px",
|
||||
padding: "12px 24px",
|
||||
borderRadius: "8px",
|
||||
backgroundColor: "#D4733B",
|
||||
color: "#fff",
|
||||
fontSize: "15px",
|
||||
fontWeight: 600,
|
||||
textDecoration: "none",
|
||||
transition: "background-color 0.15s ease",
|
||||
}}
|
||||
onMouseEnter={(e) => (e.currentTarget.style.backgroundColor = "#C0632F")}
|
||||
onMouseLeave={(e) => (e.currentTarget.style.backgroundColor = "#D4733B")}
|
||||
>
|
||||
Get started with the API
|
||||
</a>
|
||||
<a
|
||||
href="/cloud/getting-started/overview"
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
gap: "6px",
|
||||
padding: "12px 24px",
|
||||
borderRadius: "8px",
|
||||
backgroundColor: "transparent",
|
||||
color: "#2C2C2C",
|
||||
fontSize: "15px",
|
||||
fontWeight: 600,
|
||||
textDecoration: "none",
|
||||
border: "1px solid #E5DDD4",
|
||||
transition: "all 0.15s ease",
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.borderColor = "#5B8A8C";
|
||||
e.currentTarget.style.color = "#5B8A8C";
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.borderColor = "#E5DDD4";
|
||||
e.currentTarget.style.color = "#2C2C2C";
|
||||
}}
|
||||
>
|
||||
Use the dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
118
docs/snippets/persona-lanes.jsx
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
const Lane = ({ title, description, links }) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
padding: "24px",
|
||||
borderRadius: "12px",
|
||||
border: "1px solid #E5DDD4",
|
||||
backgroundColor: "#fff",
|
||||
transition: "border-color 0.15s ease, box-shadow 0.15s ease",
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.borderColor = "#7BA3A5";
|
||||
e.currentTarget.style.boxShadow = "0 4px 12px rgba(0,0,0,0.06)";
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.borderColor = "#E5DDD4";
|
||||
e.currentTarget.style.boxShadow = "none";
|
||||
}}
|
||||
>
|
||||
<h3
|
||||
style={{
|
||||
fontSize: "16px",
|
||||
fontWeight: 600,
|
||||
color: "#1a1a1a",
|
||||
margin: "0 0 6px 0",
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</h3>
|
||||
<p
|
||||
style={{
|
||||
fontSize: "14px",
|
||||
color: "#6B6560",
|
||||
margin: "0 0 20px 0",
|
||||
lineHeight: 1.5,
|
||||
}}
|
||||
>
|
||||
{description}
|
||||
</p>
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
|
||||
{links.map((link, i) => (
|
||||
<a
|
||||
key={i}
|
||||
href={link.href}
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
padding: "8px 12px",
|
||||
borderRadius: "6px",
|
||||
backgroundColor: "rgba(250, 246, 241, 0.6)",
|
||||
color: "#2C2C2C",
|
||||
fontSize: "14px",
|
||||
fontWeight: 500,
|
||||
textDecoration: "none",
|
||||
transition: "background-color 0.12s ease, color 0.12s ease",
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.backgroundColor = "rgba(91, 138, 140, 0.08)";
|
||||
e.currentTarget.style.color = "#5B8A8C";
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.backgroundColor = "rgba(250, 246, 241, 0.6)";
|
||||
e.currentTarget.style.color = "#2C2C2C";
|
||||
}}
|
||||
>
|
||||
<span>{link.label}</span>
|
||||
<span style={{ fontSize: "12px", opacity: 0.5 }}>→</span>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const PersonaLanes = () => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: "repeat(auto-fit, minmax(260px, 1fr))",
|
||||
gap: "16px",
|
||||
margin: "0 0 16px 0",
|
||||
}}
|
||||
>
|
||||
<Lane
|
||||
title="Automate without code"
|
||||
description="Use the dashboard to run tasks and build workflows visually."
|
||||
links={[
|
||||
{ label: "Dashboard overview", href: "/cloud/getting-started/overview" },
|
||||
{ label: "Run your first task", href: "/cloud/getting-started/run-your-first-task" },
|
||||
{ label: "Build a workflow", href: "/cloud/building-workflows/build-a-workflow" },
|
||||
{ label: "Connect to Zapier", href: "/integrations/zapier" },
|
||||
]}
|
||||
/>
|
||||
<Lane
|
||||
title="Build with the API"
|
||||
description="Integrate browser automation into your product with Python, TypeScript, or REST."
|
||||
links={[
|
||||
{ label: "API quickstart", href: "/getting-started/quickstart" },
|
||||
{ label: "Python SDK", href: "/sdk-reference/overview" },
|
||||
{ label: "TypeScript SDK", href: "/ts-sdk-reference/overview" },
|
||||
{ label: "API reference", href: "/api-reference" },
|
||||
]}
|
||||
/>
|
||||
<Lane
|
||||
title="Self-host"
|
||||
description="Run Skyvern on your own infrastructure with your own LLM keys."
|
||||
links={[
|
||||
{ label: "Deployment overview", href: "/self-hosted/overview" },
|
||||
{ label: "Docker setup", href: "/self-hosted/docker" },
|
||||
{ label: "LLM configuration", href: "/self-hosted/llm-configuration" },
|
||||
{ label: "Kubernetes", href: "/self-hosted/kubernetes" },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
93
docs/snippets/use-case-grid.jsx
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
const UseCase = ({ title, description, href }) => {
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
style={{
|
||||
display: "block",
|
||||
padding: "20px",
|
||||
borderRadius: "10px",
|
||||
border: "1px solid #E5DDD4",
|
||||
backgroundColor: "#fff",
|
||||
textDecoration: "none",
|
||||
color: "inherit",
|
||||
transition: "border-color 0.15s ease, box-shadow 0.15s ease",
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.borderColor = "#7BA3A5";
|
||||
e.currentTarget.style.boxShadow = "0 4px 12px rgba(0,0,0,0.06)";
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.borderColor = "#E5DDD4";
|
||||
e.currentTarget.style.boxShadow = "none";
|
||||
}}
|
||||
>
|
||||
<h4
|
||||
style={{
|
||||
fontSize: "14px",
|
||||
fontWeight: 600,
|
||||
color: "#1a1a1a",
|
||||
margin: "0 0 4px 0",
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</h4>
|
||||
<p
|
||||
style={{
|
||||
fontSize: "13px",
|
||||
color: "#6B6560",
|
||||
margin: 0,
|
||||
lineHeight: 1.5,
|
||||
}}
|
||||
>
|
||||
{description}
|
||||
</p>
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
export const UseCaseGrid = () => {
|
||||
return (
|
||||
<div>
|
||||
<h3
|
||||
style={{
|
||||
fontSize: "15px",
|
||||
fontWeight: 600,
|
||||
color: "#6B6560",
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: "0.05em",
|
||||
margin: "0 0 12px 0",
|
||||
}}
|
||||
>
|
||||
Popular use cases
|
||||
</h3>
|
||||
<div
|
||||
style={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))",
|
||||
gap: "12px",
|
||||
}}
|
||||
>
|
||||
<UseCase
|
||||
title="Download invoices"
|
||||
description="Log into vendor portals, find invoices, download PDFs."
|
||||
href="/cookbooks/bulk-invoice-downloader"
|
||||
/>
|
||||
<UseCase
|
||||
title="Fill forms at scale"
|
||||
description="Submit applications, registrations, and compliance forms."
|
||||
href="/cookbooks/job-application-filler"
|
||||
/>
|
||||
<UseCase
|
||||
title="Extract data from websites"
|
||||
description="Pull structured data from any site without an API."
|
||||
href="/running-automations/extract-structured-data"
|
||||
/>
|
||||
<UseCase
|
||||
title="Healthcare portal automation"
|
||||
description="Extract patient demographics and billing data from EHR portals."
|
||||
href="/cookbooks/healthcare-portal-data"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
651
docs/style.css
Normal file
|
|
@ -0,0 +1,651 @@
|
|||
/* ============================================
|
||||
Skyvern Docs — Editorial Bento Grid
|
||||
Warm brand + structured grid aesthetic
|
||||
============================================ */
|
||||
|
||||
/* --- Brand Tokens (navy product palette + warm landing page) --- */
|
||||
:root {
|
||||
--sk-cream: #F8F5EF;
|
||||
--sk-cream-dark: #EFEBE4;
|
||||
--sk-navy: #1B2559;
|
||||
--sk-navy-light: #2B3674;
|
||||
--sk-navy-faint: #EEF0F8;
|
||||
--sk-blue: #4A6CF7;
|
||||
--sk-blue-light: #7B93FA;
|
||||
--sk-dark: #1B2559;
|
||||
--sk-dark-hover: #2B3674;
|
||||
--sk-charcoal: #1B2038;
|
||||
--sk-text-muted: #68697B;
|
||||
--sk-border: #D6CEC4;
|
||||
--sk-border-hover: #4A6CF7;
|
||||
--sk-shadow: 0 1px 3px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.03);
|
||||
--sk-shadow-hover: 0 4px 12px rgba(27, 37, 89, 0.1), 0 2px 4px rgba(0, 0, 0, 0.04);
|
||||
--sk-radius: 10px;
|
||||
--sk-mono: "JetBrains Mono", "Fira Code", "SF Mono", "Cascadia Code", monospace;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================
|
||||
HOMEPAGE — Page wrapper (horizontal padding)
|
||||
============================================= */
|
||||
|
||||
.sk-page {
|
||||
max-width: 1100px;
|
||||
margin: 0 auto;
|
||||
padding: 0 40px;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.sk-page {
|
||||
padding: 0 20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* =============================================
|
||||
HOMEPAGE — Hero
|
||||
============================================= */
|
||||
|
||||
.sk-hero {
|
||||
border: 1px solid var(--sk-border);
|
||||
border-radius: 2px;
|
||||
margin-bottom: 1px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Version badge */
|
||||
.sk-version-badge {
|
||||
font-family: var(--sk-mono) !important;
|
||||
font-size: 10px !important;
|
||||
letter-spacing: 0.04em !important;
|
||||
padding: 3px 8px !important;
|
||||
border-radius: 3px !important;
|
||||
border: 1px solid var(--sk-border) !important;
|
||||
color: var(--sk-blue) !important;
|
||||
text-decoration: none !important;
|
||||
transition: border-color 0.15s ease !important;
|
||||
}
|
||||
|
||||
.sk-version-badge:hover {
|
||||
border-color: var(--sk-blue) !important;
|
||||
}
|
||||
|
||||
.sk-hero-inner {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0;
|
||||
min-height: 380px;
|
||||
}
|
||||
|
||||
.sk-hero-left {
|
||||
padding: 48px 40px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sk-hero-right {
|
||||
padding: 32px 40px 32px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-left: 1px solid var(--sk-border);
|
||||
}
|
||||
|
||||
.sk-hero-title {
|
||||
font-size: 38px;
|
||||
font-weight: 700;
|
||||
line-height: 1.12;
|
||||
letter-spacing: -0.03em;
|
||||
margin: 0 0 16px 0;
|
||||
color: var(--sk-charcoal);
|
||||
}
|
||||
|
||||
.sk-hero-accent {
|
||||
color: var(--sk-blue);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.sk-hero-sub {
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
color: var(--sk-text-muted);
|
||||
margin: 0 0 28px 0;
|
||||
max-width: 440px;
|
||||
}
|
||||
|
||||
.sk-hero-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* --- Monospace utility --- */
|
||||
.sk-mono {
|
||||
font-family: var(--sk-mono) !important;
|
||||
font-size: 11px !important;
|
||||
letter-spacing: 0.04em !important;
|
||||
}
|
||||
|
||||
/* --- Label (section markers like "01 — NO CODE") --- */
|
||||
.sk-label {
|
||||
font-family: var(--sk-mono) !important;
|
||||
font-size: 11px !important;
|
||||
font-weight: 500 !important;
|
||||
letter-spacing: 0.08em !important;
|
||||
text-transform: uppercase !important;
|
||||
color: var(--sk-text-muted) !important;
|
||||
margin: 0 0 12px 0 !important;
|
||||
}
|
||||
|
||||
/* --- Terminal block --- */
|
||||
.sk-terminal {
|
||||
width: 100%;
|
||||
max-width: 360px;
|
||||
border: 1px solid var(--sk-border);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
background: var(--sk-charcoal);
|
||||
}
|
||||
|
||||
.sk-terminal-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 10px 14px;
|
||||
background: #1a1a1a;
|
||||
border-bottom: 1px solid #333;
|
||||
}
|
||||
|
||||
.sk-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.sk-dot-red { background: #ff5f56; }
|
||||
.sk-dot-yellow { background: #ffbd2e; }
|
||||
.sk-dot-green { background: #27c93f; }
|
||||
|
||||
.sk-terminal-title {
|
||||
font-family: var(--sk-mono);
|
||||
font-size: 11px;
|
||||
color: #888;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.sk-terminal-body {
|
||||
padding: 14px 16px;
|
||||
}
|
||||
|
||||
.sk-terminal-body p {
|
||||
margin: 0 0 4px 0 !important;
|
||||
font-size: 11.5px !important;
|
||||
line-height: 1.6 !important;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.sk-t-teal { color: #7B93FA !important; }
|
||||
.sk-t-orange { color: #F7C948 !important; }
|
||||
.sk-t-muted { color: #555 !important; }
|
||||
|
||||
/* Blinking cursor */
|
||||
.sk-cursor {
|
||||
animation: sk-blink 1s step-end infinite;
|
||||
color: #7B93FA;
|
||||
}
|
||||
|
||||
@keyframes sk-blink {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0; }
|
||||
}
|
||||
|
||||
|
||||
/* =============================================
|
||||
HOMEPAGE — Bento Grid System
|
||||
============================================= */
|
||||
|
||||
.sk-bento-row {
|
||||
display: grid;
|
||||
gap: 1px;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
|
||||
.sk-bento-3col { grid-template-columns: repeat(3, 1fr); }
|
||||
.sk-bento-2col { grid-template-columns: repeat(2, 1fr); }
|
||||
.sk-bento-4col { grid-template-columns: repeat(4, 1fr); }
|
||||
|
||||
.sk-bento-cell {
|
||||
border: 1px solid var(--sk-border);
|
||||
border-radius: 2px;
|
||||
padding: 28px 24px;
|
||||
background: transparent;
|
||||
position: relative;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.sk-bento-cell:hover {
|
||||
background-color: rgba(74, 108, 247, 0.03);
|
||||
}
|
||||
|
||||
/* Linked cells */
|
||||
a.sk-bento-cell-link {
|
||||
text-decoration: none !important;
|
||||
color: inherit !important;
|
||||
display: block;
|
||||
}
|
||||
|
||||
a.sk-bento-cell-link:hover {
|
||||
background-color: rgba(74, 108, 247, 0.04);
|
||||
}
|
||||
|
||||
a.sk-bento-cell-link:hover .sk-arrow-lg,
|
||||
a.sk-bento-cell-link:hover .sk-arrow-sm {
|
||||
color: var(--sk-blue) !important;
|
||||
}
|
||||
|
||||
/* --- Cell typography --- */
|
||||
|
||||
.sk-cell-title {
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
margin: 0 0 6px 0;
|
||||
color: var(--sk-charcoal);
|
||||
}
|
||||
|
||||
.sk-cell-desc {
|
||||
font-size: 14px;
|
||||
color: var(--sk-text-muted);
|
||||
margin: 0 0 20px 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.sk-cell-title-sm {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
margin: 0 0 4px 0;
|
||||
color: var(--sk-charcoal);
|
||||
}
|
||||
|
||||
.sk-cell-desc-sm {
|
||||
font-size: 13px;
|
||||
color: var(--sk-text-muted);
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.sk-bento-cell-sm {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* --- Links inside cells --- */
|
||||
|
||||
.sk-cell-links {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.sk-cell-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 7px 10px;
|
||||
font-size: 13.5px;
|
||||
font-weight: 500;
|
||||
color: var(--sk-charcoal) !important;
|
||||
text-decoration: none !important;
|
||||
border-radius: 3px;
|
||||
transition: background-color 0.12s ease, color 0.12s ease;
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.sk-cell-link:hover {
|
||||
background-color: rgba(74, 108, 247, 0.06);
|
||||
color: var(--sk-blue) !important;
|
||||
}
|
||||
|
||||
/* --- Arrows --- */
|
||||
|
||||
.sk-arrow {
|
||||
font-family: var(--sk-mono);
|
||||
font-size: 12px;
|
||||
opacity: 0.35;
|
||||
transition: opacity 0.12s ease, color 0.12s ease;
|
||||
}
|
||||
|
||||
.sk-cell-link:hover .sk-arrow {
|
||||
opacity: 1;
|
||||
color: var(--sk-blue);
|
||||
}
|
||||
|
||||
.sk-arrow-lg {
|
||||
font-family: var(--sk-mono) !important;
|
||||
font-size: 18px !important;
|
||||
position: absolute;
|
||||
top: 24px;
|
||||
right: 24px;
|
||||
opacity: 0.25;
|
||||
transition: opacity 0.15s ease;
|
||||
color: var(--sk-text-muted) !important;
|
||||
}
|
||||
|
||||
.sk-arrow-sm {
|
||||
font-family: var(--sk-mono) !important;
|
||||
font-size: 14px !important;
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
opacity: 0.25;
|
||||
transition: opacity 0.15s ease;
|
||||
color: var(--sk-text-muted) !important;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================
|
||||
HOMEPAGE — Buttons
|
||||
============================================= */
|
||||
|
||||
.sk-btn-primary {
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
padding: 11px 22px !important;
|
||||
border-radius: 6px !important;
|
||||
background-color: var(--sk-dark) !important;
|
||||
color: #fff !important;
|
||||
font-size: 14px !important;
|
||||
font-weight: 600 !important;
|
||||
text-decoration: none !important;
|
||||
transition: background-color 0.15s ease !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.sk-btn-primary:hover {
|
||||
background-color: var(--sk-dark-hover) !important;
|
||||
}
|
||||
|
||||
.sk-btn-secondary {
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
padding: 11px 22px !important;
|
||||
border-radius: 4px !important;
|
||||
background-color: transparent !important;
|
||||
color: var(--sk-charcoal) !important;
|
||||
font-size: 14px !important;
|
||||
font-weight: 600 !important;
|
||||
text-decoration: none !important;
|
||||
border: 1px solid var(--sk-border) !important;
|
||||
transition: border-color 0.15s ease, color 0.15s ease !important;
|
||||
}
|
||||
|
||||
.sk-btn-secondary:hover {
|
||||
border-color: var(--sk-blue) !important;
|
||||
color: var(--sk-charcoal) !important;
|
||||
}
|
||||
|
||||
|
||||
/* --- Use case left-border accents --- */
|
||||
|
||||
.sk-usecase-teal {
|
||||
border-left: 3px solid var(--sk-blue) !important;
|
||||
}
|
||||
|
||||
.sk-usecase-orange {
|
||||
border-left: 3px solid var(--sk-dark) !important;
|
||||
}
|
||||
|
||||
|
||||
/* =============================================
|
||||
HOMEPAGE — Footer CTA
|
||||
============================================= */
|
||||
|
||||
.sk-footer-cta {
|
||||
border: 1px solid var(--sk-border);
|
||||
border-radius: 2px;
|
||||
margin-top: 1px;
|
||||
padding: 20px 24px;
|
||||
}
|
||||
|
||||
.sk-footer-cta-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.sk-footer-cta-text {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--sk-charcoal);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sk-footer-cta-links {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.sk-footer-link {
|
||||
font-family: var(--sk-mono) !important;
|
||||
font-size: 12px !important;
|
||||
letter-spacing: 0.04em !important;
|
||||
color: var(--sk-text-muted) !important;
|
||||
text-decoration: none !important;
|
||||
transition: color 0.15s ease !important;
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.sk-footer-link:hover {
|
||||
color: var(--sk-blue) !important;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.sk-footer-cta-inner {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* =============================================
|
||||
RESPONSIVE
|
||||
============================================= */
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.sk-hero-inner {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.sk-hero-right {
|
||||
border-left: none;
|
||||
border-top: 1px solid var(--sk-border);
|
||||
padding: 24px;
|
||||
}
|
||||
.sk-bento-3col {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.sk-bento-4col {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.sk-bento-2col,
|
||||
.sk-bento-4col {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.sk-hero-left {
|
||||
padding: 32px 24px;
|
||||
}
|
||||
.sk-hero-title {
|
||||
font-size: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* =============================================
|
||||
EXISTING — Cards, Tables, Links, etc.
|
||||
(non-homepage styles)
|
||||
============================================= */
|
||||
|
||||
[class*="Card"],
|
||||
.card {
|
||||
border: 1px solid var(--sk-border) !important;
|
||||
border-radius: 12px !important;
|
||||
box-shadow: var(--sk-shadow) !important;
|
||||
transition: box-shadow 0.2s ease, border-color 0.2s ease !important;
|
||||
}
|
||||
|
||||
[class*="Card"]:hover,
|
||||
.card:hover {
|
||||
box-shadow: var(--sk-shadow-hover) !important;
|
||||
border-color: var(--sk-border-hover) !important;
|
||||
}
|
||||
|
||||
article img {
|
||||
border: 1px solid var(--sk-border) !important;
|
||||
border-radius: var(--sk-radius) !important;
|
||||
box-shadow: var(--sk-shadow) !important;
|
||||
}
|
||||
|
||||
table {
|
||||
border-color: var(--sk-border) !important;
|
||||
border-radius: var(--sk-radius) !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: var(--sk-cream-dark) !important;
|
||||
border-color: var(--sk-border) !important;
|
||||
color: var(--sk-charcoal) !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
td {
|
||||
border-color: var(--sk-border) !important;
|
||||
}
|
||||
|
||||
tr:nth-child(even) td {
|
||||
background-color: rgba(250, 246, 241, 0.5) !important;
|
||||
}
|
||||
|
||||
article a:not([class]) {
|
||||
color: var(--sk-blue) !important;
|
||||
text-decoration: none !important;
|
||||
border-bottom: 1px solid transparent !important;
|
||||
transition: color 0.15s ease, border-color 0.15s ease !important;
|
||||
}
|
||||
|
||||
article a:not([class]):hover {
|
||||
color: var(--sk-dark) !important;
|
||||
border-bottom-color: var(--sk-dark) !important;
|
||||
}
|
||||
|
||||
[class*="callout"],
|
||||
[class*="Callout"],
|
||||
[class*="note"],
|
||||
[class*="Note"] {
|
||||
border-left-color: var(--sk-blue) !important;
|
||||
border-radius: 0 var(--sk-radius) var(--sk-radius) 0 !important;
|
||||
background-color: var(--sk-navy-faint) !important;
|
||||
}
|
||||
|
||||
[class*="warning"],
|
||||
[class*="Warning"] {
|
||||
border-left-color: #E5A236 !important;
|
||||
background-color: #FEF9EE !important;
|
||||
}
|
||||
|
||||
[class*="Accordion"],
|
||||
[class*="accordion"],
|
||||
details {
|
||||
border-color: var(--sk-border) !important;
|
||||
border-radius: var(--sk-radius) !important;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none !important;
|
||||
height: 1px !important;
|
||||
background: linear-gradient(90deg, transparent 0%, var(--sk-blue-light) 20%, var(--sk-blue) 50%, var(--sk-blue-light) 80%, transparent 100%) !important;
|
||||
opacity: 0.3 !important;
|
||||
margin: 2rem 0 !important;
|
||||
}
|
||||
|
||||
[class*="Step"] [class*="number"],
|
||||
[class*="step"] [class*="number"],
|
||||
[class*="Steps"] [class*="indicator"] {
|
||||
background-color: var(--sk-blue) !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
[data-active="true"],
|
||||
[aria-current="page"] {
|
||||
color: var(--sk-blue) !important;
|
||||
}
|
||||
|
||||
#navbar,
|
||||
nav[class*="Navbar"],
|
||||
header[class*="header"] {
|
||||
border-bottom: 1px solid var(--sk-border) !important;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background-color: rgba(74, 108, 247, 0.15);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--sk-cream);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--sk-border);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--sk-blue-light);
|
||||
}
|
||||
|
||||
|
||||
/* =============================================
|
||||
DARK MODE
|
||||
============================================= */
|
||||
|
||||
.dark,
|
||||
[data-theme="dark"] {
|
||||
--sk-cream: #1C1917;
|
||||
--sk-cream-dark: #252220;
|
||||
--sk-navy-faint: rgba(74, 108, 247, 0.08);
|
||||
--sk-dark: #7B93FA;
|
||||
--sk-dark-hover: #93A7FB;
|
||||
--sk-charcoal: #F5F0EB;
|
||||
--sk-text-muted: #A8A29E;
|
||||
--sk-border: #2E2A26;
|
||||
--sk-border-hover: #4A6CF7;
|
||||
--sk-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||
--sk-shadow-hover: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.dark .sk-terminal,
|
||||
[data-theme="dark"] .sk-terminal {
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
.dark .sk-cell-link:hover,
|
||||
[data-theme="dark"] .sk-cell-link:hover {
|
||||
background-color: rgba(74, 108, 247, 0.1);
|
||||
}
|
||||
|
||||
.dark tr:nth-child(even) td,
|
||||
[data-theme="dark"] tr:nth-child(even) td {
|
||||
background-color: rgba(28, 25, 23, 0.5) !important;
|
||||
}
|
||||
|
||||
.dark ::-webkit-scrollbar-track,
|
||||
[data-theme="dark"] ::-webkit-scrollbar-track {
|
||||
background: #1C1917;
|
||||
}
|
||||