stably-cli

Use the Stably CLI to create, run, fix, and maintain Playwright tests in the bloom-tests repo. Use when running tests (stably test), auto-fixing failures (stably fix), or generating new tests from a prompt (stably create).

9 stars

Best use case

stably-cli is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Use the Stably CLI to create, run, fix, and maintain Playwright tests in the bloom-tests repo. Use when running tests (stably test), auto-fixing failures (stably fix), or generating new tests from a prompt (stably create).

Teams using stably-cli should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/stably-cli/SKILL.md --create-dirs "https://raw.githubusercontent.com/exiao/skills/main/external-services/stably-cli/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/stably-cli/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How stably-cli Compares

Feature / Agentstably-cliStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Use the Stably CLI to create, run, fix, and maintain Playwright tests in the bloom-tests repo. Use when running tests (stably test), auto-fixing failures (stably fix), or generating new tests from a prompt (stably create).

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Stably CLI

Source: https://skills.sh/stablyai/agent-skills/stably-cli

AI-assisted Playwright test management: create, run, fix, and maintain tests via CLI.

## Pre-flight

```bash
stably --version   # verify installed
# If not found: npm install -g stably
```

Requires Node.js 20+, Playwright, and a Stably account.

## Command Reference

| Intent | Command |
|--------|---------|
| Generate test from prompt | `stably create "description"` |
| Generate test from branch diff | `stably create` (no prompt) |
| Run tests | `stably test` |
| Run tests with remote env | `stably --env staging test` |
| Fix failing tests | `stably fix [runId]` |
| List recent runs | `stably runs list` |
| View run details | `stably runs view <runId>` |
| Initialize project | `stably init` |
| Install browsers | `stably install [--with-deps]` |
| List remote environments | `stably env list` |
| Inspect env variables | `stably env inspect <name>` |
| Auth | `stably login / logout / whoami` |
| Update CLI | `stably upgrade [--check]` |

**Do NOT run `stably` (no args)** — that's an interactive AI chat for humans only.

## Global Options

| Option | Description |
|--------|-------------|
| `--cwd <path>` / `-C` | Change working directory |
| `--env <name>` | Load vars from remote Stably environment |
| `--env-file <path>` | Load vars from local file (repeatable) |
| `--verbose` / `-v` | Verbose logging |
| `--no-telemetry` | Disable telemetry |

Env var precedence (highest to lowest): Stably auth (`STABLY_API_KEY`) > `--env` > `--env-file` > `process.env`

## Inspecting Runs

Use `stably runs` to investigate failures without browser auth (dashboard requires login we can't automate):

```bash
stably runs list                    # recent runs with status
stably runs view <runId>            # details: status, branch, commit, pass/fail/timeout counts, failed test names + errors
```

The run ID is the slug from the dashboard URL (e.g. `ss8xdbaac1rcwm3ikcnkge0u` from `.../history/ss8xdbaac1rcwm3ikcnkge0u`).

## Core Commands

### stably create [prompt...]

Generates tests from a prompt or infers from branch diff when no prompt given.

```bash
stably create "test the checkout flow"
stably create              # infer from diff
stably create "test registration" --output ./e2e
```

Prompt tips: be specific about user flows, UI elements, auth requirements, and error states.

### stably test

Runs Playwright tests with Stably reporter. Auto-enables `--trace=on`. All Playwright CLI options pass through:

```bash
stably test --headed --project=chromium --workers=4
stably test --grep="login" tests/login.spec.ts
stably --env staging test --headed
```

### stably fix [runId]

Fixes failing tests using AI analysis of traces, screenshots, logs, and DOM state.

Run ID resolution: explicit arg > CI env (`GITHUB_RUN_ID`) > `.stably/last-run.json` (24h cache). Requires git repo.

```bash
stably fix           # auto-detect last run
stably fix abc123    # explicit run ID
```

Typical workflow: `stably test` > (failures?) > `stably fix` > `stably test`

**Agent fix workflow (recommended):**
1. `stably runs view <runId>` to understand failures before fixing
2. `git pull origin main` to ensure you're on latest (stably fix edits files in-place)
3. `stably fix <runId>` with 600s+ timeout (can take 10+ min; output is mostly spinner noise)
4. Check `git diff` to see what stably actually changed. The terminal output is too noisy to parse
5. If main was updated since the failing run, stably's edits may conflict. Create a worktree from origin/main, manually apply the relevant changes, and PR from there
6. Review the diff critically: stably sometimes uses brittle selectors (`.nth(5)`, `.first()`) or overly generic `aiAssert`. Prefer explicit selectors (ticker symbols, role+name) over AI-driven assertions when possible

## Long-Running Commands (Important for Agents)

`stably create` and `stably fix` are AI-powered and can take **several minutes**.
- Use `exec` with a long timeout (600s+) or background mode
- All other commands complete in seconds

## Bloom-Specific Setup

Prefer the repo-local CLI if `stably` is not globally installed. Install dependencies first, then call `./node_modules/.bin/stably` directly so verification does not depend on global npm state.

```bash
cd ~/projects/bloom-tests
npm install --no-audit --no-fund
source ~/.hermes/.env
STABLY_API_KEY=$STABLY_API_KEY \
STABLY_PROJECT_ID=$STABLY_PROJECT_ID \
BASE_URL=https://bloom.onrender.com \
./node_modules/.bin/stably test
```

To fix after a failing run:
```bash
source ~/.hermes/.env
STABLY_API_KEY=$STABLY_API_KEY STABLY_PROJECT_ID=$STABLY_PROJECT_ID ./node_modules/.bin/stably fix
```

If a test run URL is produced but `stably runs view` fails because `stably` is not on PATH, use the local binary:

```bash
source ~/.hermes/.env
STABLY_API_KEY=$STABLY_API_KEY STABLY_PROJECT_ID=$STABLY_PROJECT_ID \
./node_modules/.bin/stably runs view <runId>
```

## Playwright Pitfalls

**`isVisible({ timeout })` does NOT wait.** Playwright's `locator.isVisible()` returns immediately regardless of any timeout option passed. The timeout is silently ignored. To wait for an optional element, use `locator.waitFor({ state: 'visible', timeout: 3000 })` inside a try/catch. This is the #1 cause of race conditions in modal dismissal guards.

```ts
// WRONG — returns immediately, modal may not have rendered yet
if (await modal.isVisible({ timeout: 3000 })) { ... }

// RIGHT — actually waits up to 3s for the element
try {
  await modal.waitFor({ state: 'visible', timeout: 3000 });
  await page.keyboard.press('Escape');
  try {
    await modal.waitFor({ state: 'hidden', timeout: 1000 });
  } catch {
    await modal.locator('..').locator('button').first().click({ force: true });
  }
} catch {
  // Modal never appeared — nothing to do
}
```

**Strict mode violations with `getByRole('button')`.** If a row or container has multiple buttons, `getByRole('button')` without `.first()` or a name filter throws a strict mode error. Always scope: `.getByRole('button').first()` or `.getByRole('button', { name: 'Bookmark' })`.

**afterAll cleanup is mandatory for state-mutating tests.** Tests that bookmark stocks, create portfolios, or modify user state MUST have an `afterAll` hook to undo those changes. Watchlist/bookmark state persists across runs and causes cascading failures in other tests. Pattern:

```ts
test.afterAll(async ({ browser }) => {
  const page = await browser.newPage();
  try {
    // Navigate and undo state changes
  } catch {
    // Cleanup target doesn't exist — nothing to do
  } finally {
    await page.close();
  }
});
```

## Bloom Test Failure Patterns

Common failure modes in bloom-tests and fixes:

**Feedback Modal Overlay:** A "Bloom experience" feedback modal overlays form elements (portfolio creation, edit flows), causing timeouts. Dismiss early using the waitFor pattern above with `page.getByRole('heading', { name: /Bloom experience/i })`.

**Company Name vs Ticker Selectors:** Bloom UI renders ticker symbols (GOOGL, MSFT) as link text, not company names. Use `{ name: /GOOGL/ }` not `{ name: 'Alphabet' }`.

**agent.act() Failures:** Replace with explicit Playwright selectors when possible. Reserve `agent.act()` for genuinely dynamic interactions where the exact selector isn't predictable.

**Search/Algolia Flakiness:** Avoid making critical Bloom QA flows depend on live search results when the same state can be reached through deterministic in-app navigation. In Stably/headless runs, stock search for `AAPL` has returned ETF-like results (`AAPW`, `AAPY`, `AAPD`) or hung before `Apple Inc` appeared. Prefer direct collection pages, ticker rows, or “Copy collection to portfolio” flows when testing portfolio mechanics. See `references/bloom-search-and-collections-flakiness.md` for a concrete repro and refactor pattern.

**Back Button Fragility:** `.getByRole('button').first()` is brittle. Use name or aria-label selectors instead.

## Required Env Vars

```bash
STABLY_API_KEY=<your-stably-api-key>
STABLY_PROJECT_ID=<your-stably-project-id>
```

## Playwright Config (Reporter Setup)

```ts
import { defineConfig } from '@playwright/test';
import { stablyReporter } from '@stablyai/playwright-test';

export default defineConfig({
  use: { trace: 'on' },
  reporter: [
    ['list'],
    stablyReporter({
      apiKey: process.env.STABLY_API_KEY,
      projectId: process.env.STABLY_PROJECT_ID,
    }),
  ],
});
```

## Troubleshooting

| Problem | Solution |
|---------|----------|
| "Not authenticated" | `stably login` |
| API key not recognized | `stably whoami` to verify |
| Tests in wrong directory | `stably create "..." --output ./tests/e2e` |
| Missing browser | `stably install --with-deps` |
| Traces not uploading | Set `trace: 'on'` in `playwright.config.ts` |
| "Run ID not found" | Run `stably test` first, then `stably fix` |
| Dashboard URL but no browser auth | Use `stably runs view <runId>` via CLI instead |

## Links

- Docs: https://docs.stably.ai
- CLI Quickstart: https://docs.stably.ai/stably2/cli-quickstart
- Dashboard: https://app.stably.ai
- API Keys: https://auth.stably.ai/org/api_keys/

Related Skills

writer

9
from exiao/skills

Write content in Eric's voice — articles, blog posts, tweets, social media posts, marketing copy, newsletter drafts. Loads WRITING-STYLE.md and enforces kill phrases.

positioning-angles

9
from exiao/skills

Use when defining product positioning, choosing strategic angles, crafting value propositions, competitive positioning, product messaging, differentiation strategy, or go-to-market angles. Also use for 'how should I position my app', 'what angle should I use', 'painkiller vs vitamin', or 'market positioning'.

outline-generator

9
from exiao/skills

Use when generating outlines, article structures, content outlines, blog outlines, planning article sections, structuring posts, breaking down topics into sections, or organizing ideas for long-form content. Also use for 'outline this', 'structure this article', or 'plan the sections'.

last30days-open

9
from exiao/skills

Use only when the user explicitly asks for the open variant of last30days, including watchlists, briefings, and history queries. Sources: Reddit, X, YouTube, web.

last30days

9
from exiao/skills

Use when researching what happened in the last 30 days on a topic. Also triggered by 'last30'. Sources: Reddit, X, YouTube, web. Produces expert-level summary with copy-paste-ready prompts.

hooks

9
from exiao/skills

Use when generating hooks, headlines, titles, and scroll-stopping openers for content. Also use when analyzing viral posts, Reels, TikToks, YouTube Shorts, or successful social examples to extract reusable hook patterns and improve hook guidance.

evaluate-content

9
from exiao/skills

Use when judging content quality OR editing/improving existing copy: shareability, readability, voice, cuttability, angle, copy sweeps.

editor-in-chief

9
from exiao/skills

Use when a first draft is complete and all Phase 1 gates are done: topic selected (seo-research), title approved (hooks), outline approved (outline-generator), draft written (writer). Runs autonomous diagnosis-prescribe-rewrite loop before Substack.

copywriting

9
from exiao/skills

Write or improve marketing copy for any surface: pages, ads, app stores, landing pages, TikTok/Meta scripts, push notifications, UGC. Combines page copy frameworks with direct response principles.

content-strategy

9
from exiao/skills

Use when building content strategy: hooks, angles, and ideas from what's trending now. Covers organic and paid creative across TikTok, X, YouTube, Meta, LinkedIn.

content-pipeline

9
from exiao/skills

Orchestrator for the 3-article content pipeline — runs research phase, spawns parallel article sub-agents, creates Typefully drafts. Use when running the full content pipeline (usually via cron at 3am).

yt-dlp

9
from exiao/skills

Download audio/video from YouTube and other sites using yt-dlp. Use when the user asks to download music, songs, albums, podcasts, or video from YouTube or similar platforms. Triggers on 'download song', 'get mp3', 'yt-dlp', 'youtube download', 'rip audio'.