Merge branch 'cl/romantic-mendel-5a2c25' into cl/hexclave-pr3

This commit is contained in:
BilalG1 2026-05-26 12:40:42 -07:00 committed by GitHub
commit fe5cb5f7d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 54 additions and 501 deletions

View File

@ -60,8 +60,6 @@
"guides/going-further/stack-app",
"guides/going-further/backend-integration",
"guides/going-further/cli",
"guides/going-further/local-emulator",
"guides/going-further/local-development",
"guides/going-further/user-metadata"
]
},
@ -142,8 +140,7 @@
"guides/other/tutorials/build-a-team-based-app",
"guides/other/tutorials/ship-production-ready-auth"
]
},
"guides/other/showcase"
}
]
}
]

View File

@ -1,6 +1,6 @@
---
title: Using Hexclave with AI
description: Teach your coding agent how to use Hexclave — via a copy-paste prompt, an installable skill, or the Hexclave MCP server.
description: Teach your coding agent how to use Hexclave — via web fetch, an installable skill, or the Hexclave MCP server.
sidebarTitle: Using Hexclave with AI
---
@ -13,18 +13,32 @@ sidebarTitle: Using Hexclave with AI
There are three ways to give a coding agent working knowledge of Hexclave. They differ only in how the instructions reach the agent — the knowledge is the same.
<CardGroup cols={3}>
<Card title="Skill" icon="sparkles" href="#option-1-skill">
<Card title="Web Fetch" icon="wand-magic-sparkles" href="#option-1-web-fetch-recommended">
Paste a one-line prompt — your agent fetches the live skill on demand.
</Card>
<Card title="Skill" icon="sparkles" href="#option-2-skill">
Install the Hexclave `SKILL.md` file so your agent loads it automatically.
</Card>
<Card title="MCP" icon="plug" href="#option-2-mcp">
<Card title="MCP" icon="plug" href="#option-3-mcp">
Connect your agent to the Hexclave MCP server for live docs and `ask_hexclave` search.
</Card>
<Card title="Prompt" icon="wand-magic-sparkles" href="#option-3-prompt">
Paste a one-line prompt — your agent fetches the live skill on demand.
</Card>
</CardGroup>
## Option 1: Skill
## Option 1: Web fetch (recommended)
Most coding agents now support web fetch out of the box, so you can simply tell your agent to use Hexclave's skill from the internet.
To do so, paste the prompt below into your coding agent:
````markdown title="One-shot prompt"
Fetch https://skill.hexclave.com and follow it for this task.
````
The fetched `SKILL.md` indexes the entire Hexclave docs sidebar and tells the agent to pull fresh content for whichever surface you're touching (auth, orgs/teams, payments, emails, analytics, the CLI). It is purely a reference — paste it whenever you want the agent to use Hexclave knowledge.
## Option 2: Skill
Install the skill once so your agent loads it automatically every time Hexclave is relevant — no copy-paste required.
@ -96,7 +110,7 @@ Install the skill once so your agent loads it automatically every time Hexclave
</Tab>
</Tabs>
## Option 2: MCP
## Option 3: MCP
The Hexclave MCP server (`https://mcp.hexclave.com/mcp`) gives your agent live access to Hexclave docs and skill via prompts, resources and an `ask_hexclave` tool that searches the docs with citations. Install it once per agent — it stays available across every project.
@ -209,16 +223,6 @@ The Hexclave MCP server (`https://mcp.hexclave.com/mcp`) gives your agent live a
</Tab>
</Tabs>
## Option 3: Prompt
No installation. Paste the prompt below into your coding agent whenever you want it to act on Hexclave. The agent fetches the latest Hexclave instructions from `skill.hexclave.com`.
````markdown title="One-shot prompt"
Fetch https://skill.hexclave.com and follow it for this task.
````
The fetched `SKILL.md` indexes the entire Hexclave docs sidebar and tells the agent to pull fresh content for whichever surface you're touching (auth, orgs/teams, payments, emails, analytics, the CLI). It is purely a reference — paste it whenever you want the agent to use Hexclave knowledge.
## Project vs. global scope
The install prompts above follow the same rule for picking project-vs-global scope:

View File

@ -1,227 +0,0 @@
---
title: "Local Development"
description: "Set up and run Hexclave locally for development and testing"
---
You can develop with Hexclave in two ways:
- Use **Hexclave Cloud from your local app**. This keeps Hexclave hosted while your app runs on your machine.
- Use the **local emulator**. This runs the Hexclave backend, dashboard, email inbox, and mock OAuth services locally.
Both workflows let you run your app with your normal framework dev server, such as `npm run dev`, `pnpm dev`, or `next dev`.
## Cloud-backed local dev
To keep Hexclave hosted while your app runs locally, create or select a Hexclave project in the dashboard, then copy the environment variables from the [setup guide](/guides/getting-started/setup) into your local `.env` file.
```env title=".env.local"
NEXT_PUBLIC_STACK_PROJECT_ID=your-project-id
STACK_SECRET_SERVER_KEY=ssk_...
```
If your project is configured to require publishable client keys, also set the public publishable key for your framework:
```env title=".env.local"
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=pck_...
```
Then start your app:
```sh title="Terminal"
npm run dev
```
Use this workflow when you want:
- Hosted dashboard settings to be the source of truth
- Real OAuth provider setup and redirect URLs
- Real email delivery behavior
- Hosted Hexclave services while your app runs locally
Cloud-backed local development uses the cloud project ID and keys in your local environment. If those values point at your production project, local sign-ins, test users, emails, OAuth accounts, and config changes affect that same production project. Create a separate cloud project for development or testing when you want cloud behavior without touching production data.
<Info>
Keep `STACK_SECRET_SERVER_KEY` server-side. In browser-exposed environments, use only the public variables for your framework, such as `NEXT_PUBLIC_STACK_PROJECT_ID`.
</Info>
## Fully local workflow: emulator-backed dev
Use the [local emulator](/guides/going-further/local-emulator) when you want an isolated Hexclave environment on your machine. The emulator is useful for testing config changes, working offline after the image is downloaded, and developing against a local `stack.config.ts` file.
The emulator requires QEMU and other system tools. Installing the Stack CLI does not install QEMU; the CLI checks for missing emulator dependencies when you run emulator commands.
Start the emulator:
```sh title="Terminal"
npx @hexclave/cli@latest emulator start
```
Open the local dashboard:
```text
http://127.0.0.1:26700
```
The backend API is available at:
```text
http://127.0.0.1:26701
```
The emulator also exposes local supporting services, including Inbucket for email testing and a mock OAuth server. See the [local emulator guide](/guides/going-further/local-emulator#ports) for the full port list.
## Run your app with emulator credentials
To connect your app to the emulator, use `emulator run`. It starts the emulator if needed, injects local project credentials into your app process, and points the SDK at the local backend.
```sh title="Terminal"
npx @hexclave/cli@latest emulator run "npm run dev" --config-file ./stack.config.ts
```
When `--config-file` is provided, the CLI maps your local `stack.config.ts` to an emulator project and injects variables such as:
```text
NEXT_PUBLIC_STACK_PROJECT_ID
STACK_SECRET_SERVER_KEY
NEXT_PUBLIC_STACK_API_URL
STACK_API_URL
```
The emulator also injects publishable client key variables, such as `NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY`, for projects that use them.
Use the public variable names that match your framework. For example, Next.js reads `NEXT_PUBLIC_STACK_*`, Vite reads `VITE_STACK_*`, and Expo reads `EXPO_PUBLIC_STACK_*`. The emulator injects all of these variants for convenience.
## Local config files
If you use config-file backed development, `stack.config.ts` becomes the local source of truth for Hexclave settings. The emulator reads that file and creates or updates a matching local project.
Create a config-driven project with the CLI:
```sh title="Terminal"
npx @hexclave/cli@latest init --mode create --apps authentication
```
Run against it locally:
```sh title="Terminal"
npx @hexclave/cli@latest emulator run "npm run dev" --config-file ./stack.config.ts
```
When you are working with Hexclave Cloud instead of the emulator, you can use the [CLI config commands](/guides/going-further/cli#config-commands) to pull and push branch config:
```sh title="Terminal"
npx @hexclave/cli@latest --project-id <project-id> config pull --config-file ./stack.config.ts
npx @hexclave/cli@latest --project-id <project-id> config push --config-file ./stack.config.ts
```
## Testing auth flows locally
### Sign-in and sign-up pages
After your app is running, visit the Stack handler routes in your app, for example:
```text
http://localhost:3000/handler/sign-in
http://localhost:3000/handler/sign-up
http://localhost:3000/handler/account-settings
```
If your app uses a different port, replace `3000` with your app's dev server port.
### Emails
In cloud-backed local dev, emails are sent according to your hosted project settings. In emulator-backed dev, emails are captured locally in Inbucket:
```text
http://127.0.0.1:26703
```
Use this for magic links, verification emails, password reset emails, and team invitations without sending real email.
### OAuth providers
In cloud-backed local dev, configure each provider's redirect URL in the provider dashboard. For Hexclave OAuth providers, the redirect URL is shown in the Stack dashboard when you configure the provider.
In emulator-backed dev, use the emulator's local services and mock OAuth flow instead of creating real provider apps. This keeps local tests isolated from production provider credentials.
## Common local development issues
### The SDK is still calling Hexclave Cloud
If your app is configured to use the emulator but requests are going to Hexclave Cloud, make sure your process received the API URL variables:
```text
STACK_API_URL=http://127.0.0.1:26701
NEXT_PUBLIC_STACK_API_URL=http://127.0.0.1:26701
```
The simplest fix is to start your app through `emulator run` instead of starting the emulator and app separately.
### Project ID or key mismatch
If you see authentication failures immediately after startup, check that all Hexclave variables come from the same project. Do not mix a cloud `NEXT_PUBLIC_STACK_PROJECT_ID` with an emulator `STACK_SECRET_SERVER_KEY`, or a publishable client key from one project with a secret server key from another.
When using `emulator run`, remove conflicting Hexclave values from your shell or `.env.local` so your app cannot accidentally mix cloud and emulator credentials.
### Redirect URL is not whitelisted
Magic links and OAuth redirects must return to an allowed domain. Add your local app origin, such as `http://localhost:3000`, to the project's allowed domains in the dashboard. If you use the emulator, add it in the local dashboard at `http://127.0.0.1:26700`.
For programmatic handling, this failure appears as `REDIRECT_URL_NOT_WHITELISTED`. See [Known Errors](/guides/other/known-errors) for how known error codes are exposed in SDK and REST responses.
### Emails do not arrive
For cloud-backed local dev, check your email provider settings and spam folder. For emulator-backed dev, open Inbucket at `http://127.0.0.1:26703`; emulator emails are captured there and are not sent to a real inbox.
### Emulator port already in use
The emulator defaults to dashboard port `26700` and backend port `26701`. If a port is already in use, override it before starting the emulator:
```sh title="Terminal"
EMULATOR_DASHBOARD_PORT=27700 \
EMULATOR_BACKEND_PORT=27701 \
npx @hexclave/cli@latest emulator start
```
See [Local Emulator](/guides/going-further/local-emulator#troubleshooting) for more emulator-specific troubleshooting.
### `run-emulator.sh` permission denied
Some npm installs can leave the bundled emulator script without executable permissions. If `stack emulator start` or `npx @hexclave/cli@latest emulator start` fails with `spawn .../run-emulator.sh EACCES`, apply execute permissions to the path shown in the error:
```sh title="Terminal"
chmod +x /path/to/node_modules/@hexclave/cli/dist/emulator/run-emulator.sh
```
For `npx`, the script path is inside npm's temporary cache and may change between runs.
### The emulator starts slowly
The first emulator start downloads the VM image and creates a fast-start snapshot. This can take a few minutes and requires several gigabytes of disk space. Later starts should be much faster.
If the emulator gets into a bad state, reset it:
```sh title="Terminal"
npx @hexclave/cli@latest emulator reset
```
This wipes emulator runtime state but keeps downloaded images.
## What to use in CI
For CI that tests your app against Hexclave Cloud, provide the same project variables you use locally:
```env
NEXT_PUBLIC_STACK_PROJECT_ID=...
STACK_SECRET_SERVER_KEY=...
```
Add `NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY` or the equivalent public variable for your framework if the project requires publishable client keys.
For CI that needs a disposable local Hexclave instance, run tests through the emulator:
```sh title="Terminal"
npx @hexclave/cli@latest emulator run "npm test" --config-file ./stack.config.ts
```
The emulator boots a local VM, so it adds more startup cost than cloud-backed tests. Use it in CI when the test needs local config-file behavior or isolated emulator state.

View File

@ -1,219 +0,0 @@
---
title: "Local Emulator"
description: "Run Hexclave locally with the QEMU emulator"
sidebarTitle: "Local Emulator"
---
The Hexclave local emulator runs the Hexclave dashboard, backend, and supporting services on your machine. It is useful when you want local-first development, config-file-backed projects, or an isolated Hexclave environment for testing.
The emulator is managed by the [Stack CLI](/guides/going-further/cli):
```sh title="Terminal"
npx @hexclave/cli@latest emulator start
```
On first start, the CLI downloads the emulator image and captures a local fast-start snapshot (the capture step runs `zstd`). This can take a few minutes and requires several gigabytes of disk space. Later starts should be much faster.
## Requirements
The emulator uses QEMU. Installing the Stack CLI does not install QEMU or the other system tools listed below. The CLI checks for the required dependencies when you run emulator commands and, on macOS or Debian/Ubuntu-style Linux, can prompt to install missing packages.
Required tools include:
- QEMU for your architecture
- `qemu-img`
- `socat`
- `curl`
- `nc`
- `lsof`
- `openssl`
- `zstd` — required on the default fresh-start path: `emulator start` captures a local snapshot using `zstd`, so installs without `zstd` hit an error instead of silently falling back to uncompressed snapshots only.
<Info>
Native architecture is fastest. Cross-architecture emulation works through QEMU software emulation but is significantly slower.
</Info>
## Start and stop
Start the emulator:
```sh title="Terminal"
npx @hexclave/cli@latest emulator start
```
Open the dashboard:
```text
http://127.0.0.1:26700
```
The default local admin credentials are:
```text
Email: local-emulator@hexclave.com
Password: LocalEmulatorPassword
```
Check health:
```sh title="Terminal"
npx @hexclave/cli@latest emulator status
```
Stop the emulator while preserving data:
```sh title="Terminal"
npx @hexclave/cli@latest emulator stop
```
Reset emulator state:
```sh title="Terminal"
npx @hexclave/cli@latest emulator reset
```
## Ports
By default, the emulator exposes these services on the host:
| Service | Default port | URL |
| --- | --- | --- |
| Dashboard | `26700` | `http://127.0.0.1:26700` |
| Backend API | `26701` | `http://127.0.0.1:26701` |
| MinIO | `26702` | `http://127.0.0.1:26702` |
| Inbucket | `26703` | `http://127.0.0.1:26703` |
| Mock OAuth server | `26704` | `http://127.0.0.1:26704` |
Override ports with environment variables:
```sh title="Terminal"
EMULATOR_DASHBOARD_PORT=27700 \
EMULATOR_BACKEND_PORT=27701 \
npx @hexclave/cli@latest emulator start
```
The app port prefix inside the VM defaults to `81`. Override it with `PORT_PREFIX` or `NEXT_PUBLIC_STACK_PORT_PREFIX`.
## Use a local config file
Pass `--config-file` to map a `stack.config.ts` file to a local emulator project.
```sh title="Terminal"
npx @hexclave/cli@latest emulator start --config-file ./stack.config.ts
```
The command prints project credentials as JSON:
```json
{
"project_id": "...",
"publishable_client_key": "pck_...",
"secret_server_key": "ssk_..."
}
```
For development servers, `emulator run` starts the emulator if needed, injects credentials into the child process, and stops the emulator when the child exits if it started that emulator instance:
```sh title="Terminal"
npx @hexclave/cli@latest emulator run "npm run dev" --config-file ./stack.config.ts
```
When `--config-file` is provided, the child process receives:
| Variable | Description |
| --- | --- |
| `STACK_PROJECT_ID` | Local emulator project ID. |
| `NEXT_PUBLIC_STACK_PROJECT_ID` | Next.js public project ID. |
| `VITE_STACK_PROJECT_ID` | Vite public project ID. |
| `EXPO_PUBLIC_STACK_PROJECT_ID` | Expo public project ID. |
| `STACK_PUBLISHABLE_CLIENT_KEY` | Publishable client key. |
| `NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY` | Next.js public publishable client key. |
| `VITE_STACK_PUBLISHABLE_CLIENT_KEY` | Vite public publishable client key. |
| `EXPO_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY` | Expo public publishable client key. |
| `STACK_SECRET_SERVER_KEY` | Secret server key. Keep this server-side. |
| `STACK_API_URL` | Backend URL, usually `http://127.0.0.1:26701`. |
| `NEXT_PUBLIC_STACK_API_URL` | Next.js public backend URL. |
| `VITE_STACK_API_URL` | Vite public backend URL. |
| `EXPO_PUBLIC_STACK_API_URL` | Expo public backend URL. |
## Pull images explicitly
`emulator start` automatically pulls the latest image when none exists. You can also pull manually:
```sh title="Terminal"
npx @hexclave/cli@latest emulator pull
```
Useful pull options:
| Option | Description |
| --- | --- |
| `--arch arm64` or `--arch amd64` | Download a specific architecture. Defaults to the current system architecture. |
| `--branch <branch>` | Pull the latest emulator release for a branch. Defaults to `dev`. |
| `--tag <tag>` | Pull a specific release tag. |
| `--repo <owner/repo>` | Pull from another GitHub repository. Defaults to `stack-auth/stack-auth`. |
| `--pr <number>` | Pull from the latest successful emulator build for a PR. |
| `--run <id>` | Pull from a specific GitHub Actions workflow run. |
| `--skip-snapshot` | Download only the disk image. The next start will cold-boot. |
List published emulator releases:
```sh title="Terminal"
npx @hexclave/cli@latest emulator list-releases
```
## Storage and state
Emulator files live under:
```text
~/.stack/emulator
```
Override this directory with `STACK_EMULATOR_HOME`.
The VM uses an overlay disk for runtime state. `emulator stop` preserves the overlay; `emulator reset` clears it.
## Troubleshooting
### GitHub rate limits or private artifacts
The CLI uses `GITHUB_TOKEN` when it is set. If not, it tries `gh auth token`. Public release downloads can work anonymously with lower rate limits, but PR and workflow-run artifact downloads require GitHub authentication.
```sh title="Terminal"
gh auth login
# or
export GITHUB_TOKEN=<token>
```
### Port already in use
Change the conflicting port with `EMULATOR_DASHBOARD_PORT`, `EMULATOR_BACKEND_PORT`, `EMULATOR_MINIO_PORT`, `EMULATOR_INBUCKET_PORT`, or `EMULATOR_MOCK_OAUTH_PORT`.
### `run-emulator.sh` permission denied
Some npm installs can leave the bundled emulator script without executable permissions. If `stack emulator start` or `npx @hexclave/cli@latest emulator start` fails with `spawn .../run-emulator.sh EACCES`, apply execute permissions to the installed script:
```sh title="Terminal"
chmod +x /path/to/node_modules/@hexclave/cli/dist/emulator/run-emulator.sh
```
For `npx`, the path is inside npm's temporary cache and may change between runs. Use the path shown in the error message.
### Wrong architecture
Use `--arch arm64` on Apple Silicon or ARM Linux, and `--arch amd64` on Intel/AMD machines.
```sh title="Terminal"
npx @hexclave/cli@latest emulator start --arch arm64
```
### Need a clean environment
Run:
```sh title="Terminal"
npx @hexclave/cli@latest emulator reset
```
This wipes local emulator state but keeps downloaded images.

View File

@ -1,22 +0,0 @@
---
title: "Showcase"
description: "See what others have built with Hexclave"
---
<div className="grid gap-6 sm:grid-cols-2">
<a href="https://browser-use.com" className="showcase-card rounded-xl border border-gray-200 dark:border-gray-800">
<img src="/images/showcase/browser-use.png" alt="Browser Use homepage" className="showcase-card-image" />
<div className="pointer-events-none absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent opacity-90" />
<div className="pointer-events-none absolute bottom-0 left-0 p-6">
<h2 className="text-2xl font-semibold text-white">Browser Use</h2>
</div>
</a>
<a href="https://over.world/" className="showcase-card rounded-xl border border-gray-200 dark:border-gray-800">
<img src="/images/showcase/over.world.png" alt="Overworld homepage" className="showcase-card-image" />
<div className="pointer-events-none absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent opacity-90" />
<div className="pointer-events-none absolute bottom-0 left-0 p-6">
<h2 className="text-2xl font-semibold text-white">Overworld</h2>
</div>
</a>
</div>

View File

@ -1044,6 +1044,36 @@ export class _StackClientAppImplIncomplete<HasTokenStore extends boolean, Projec
}
private _extractRefreshTokenFromCookieMap(cookies: cookie.Cookies): { refreshToken: string | null, updatedAt: number | null } {
const { legacyNames, structuredPrefixes } = this._getRefreshTokenCookieNamePatterns();
const currentStructuredPrefixes = [
`${this._refreshTokenCookieName}--`,
`__Host-${this._refreshTokenCookieName}--`,
];
const getNewestStructuredCookie = (prefixes: string[]) => {
let selected: { refreshToken: string, updatedAt: number | null } | null = null;
for (const [name, value] of Object.entries(cookies)) {
if (!prefixes.some(prefix => name.startsWith(prefix))) continue;
const parsed = this._parseStructuredRefreshCookie(value);
if (!parsed) continue;
const candidateUpdatedAt = parsed.updatedAt ?? Number.NEGATIVE_INFINITY;
const selectedUpdatedAt = selected?.updatedAt ?? Number.NEGATIVE_INFINITY;
if (!selected || candidateUpdatedAt > selectedUpdatedAt) {
selected = parsed;
}
}
return selected;
};
const currentStructuredCookie = getNewestStructuredCookie(currentStructuredPrefixes);
if (currentStructuredCookie) {
return {
refreshToken: currentStructuredCookie.refreshToken,
updatedAt: currentStructuredCookie.updatedAt ?? null,
};
}
// Legacy cookies are migration-only. Once a Hexclave cookie exists, it wins;
// otherwise an old SDK tab with an anonymous legacy cookie can sign a
// new-SDK tab out through the compatibility read.
for (const name of legacyNames) {
const value = cookies[name];
if (value) {
@ -1051,17 +1081,7 @@ export class _StackClientAppImplIncomplete<HasTokenStore extends boolean, Projec
}
}
let selected: { refreshToken: string, updatedAt: number | null } | null = null;
for (const [name, value] of Object.entries(cookies)) {
if (!structuredPrefixes.some(prefix => name.startsWith(prefix))) continue;
const parsed = this._parseStructuredRefreshCookie(value);
if (!parsed) continue;
const candidateUpdatedAt = parsed.updatedAt ?? Number.NEGATIVE_INFINITY;
const selectedUpdatedAt = selected?.updatedAt ?? Number.NEGATIVE_INFINITY;
if (!selected || candidateUpdatedAt > selectedUpdatedAt) {
selected = parsed;
}
}
const selected = getNewestStructuredCookie(structuredPrefixes);
if (!selected) {
return { refreshToken: null, updatedAt: null };