Skip to content
Development
Skill

/test-it-locally

Test Riptide changes against the local devstack through the UI, HumanLayer CLI, and database. Use for local verification, agent-browser checks, local task or session creation, and devstack setup.

BOOST
From plugin
humanlayer
12k56 skills
Install
$ npx -y skills add humanlayer/humanlayer --skill test-it-locally --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/test-it-locally

Context preview

The summary Claude sees to decide when to auto-load this skill.

Test Riptide changes against the local devstack through the UI, HumanLayer CLI, and database. Use for local verification, agent-browser checks, local task or session creation, and devstack setup.

SKILL.md

test-it-locally.SKILL.md
name: test-it-locally
description: Test Riptide changes against the local devstack through the UI, HumanLayer CLI, and database. Use for local verification, agent-browser checks, local task or session creation, and devstack setup.

Test It Locally

Test the changed behavior and its stored state, not just whether the app loads.

Workflow

1. Inspect the worktree stack. Read the whole plaintext output: it includes the local WorkOS organization, routes, ports, logs, generated env state, and an API health line. Sync only if it is missing or stale; `--compose --seed` is usually already done, then run `status` again.

bun --bun run devstack status
bun --bun run devstack sync --compose --seed

2. Use the `API healthcheck` line from the full `bun --bun run devstack status` output. `passed` means the app stack is ready; `failed` means it is not running.

3. If it failed, start Riptide in a tmux session that excludes the parent daemon's identity. This keeps the initial process and any later panes on the devstack's local identity. Use `riptide:native` only when the native shell matters.

STACK_ID="$(bun --bun run devstack status --json | jq -r '.id')" && \
TMUX_SESSION="riptide-$STACK_ID" && \
tmux new-session -d -s "$TMUX_SESSION" -c "$PWD" \
  "env -u DAEMON_IDENTITY -u RIPTIDE_DAEMON_EXPECTED_IDENTITY bun --bun run riptide" && \
tmux set-environment -u -t "$TMUX_SESSION" DAEMON_IDENTITY && \
tmux set-environment -u -t "$TMUX_SESSION" RIPTIDE_DAEMON_EXPECTED_IDENTITY
tmux attach -t "$TMUX_SESSION"

Do not use `tmux set-environment -gu`; the tmux server is shared by other devstacks.

4. Open the worktree URL headless with a browser session and profile keyed by the devstack ID. The named session isolates the running agent-browser daemon, while the profile persists cookies, IndexedDB, and cache. Both are needed so multiple devstacks can run browser checks in parallel without sharing state. Do not use `--session-name`, the fixed `riptide` profile, or a fixed localhost port.

DEVSTACK_STATUS="$(bun --bun run devstack status --json)" && \
export DEVSTACK_ID="$(jq -r '.id' <<<"$DEVSTACK_STATUS")" && \
export AGENT_BROWSER_SESSION="riptide-$DEVSTACK_ID" && \
export AGENT_BROWSER_PROFILE="$HOME/.agent-browser/profiles/riptide-$DEVSTACK_ID" && \
APP_URL="$(jq -r '.routes.ui' <<<"$DEVSTACK_STATUS")" && \
agent-browser open "$APP_URL" && agent-browser wait --load networkidle && agent-browser get url && agent-browser snapshot -i

Set `AGENT_BROWSER_SESSION` and `AGENT_BROWSER_PROFILE` from status at the start of each new shell call that runs agent-browser. All agent-browser commands in that call then target only this devstack. Do not run an unscoped `agent-browser close`, because it closes the default session rather than this stack's session.

If this shows WorkOS login, use the shared sandbox test user from the root `.env`. Read the values without printing them, and refer to them by variable name in every `agent-browser` command. Never put a credential value in a command, response, screenshot, log, or committed file.

set -a
source .env
set +a
DEVSTACK_STATUS="$(bun --bun run devstack status --json)" && \
export DEVSTACK_ID="$(jq -r '.id' <<<"$DEVSTACK_STATUS")" && \
export AGENT_BROWSER_SESSION="riptide-$DEVSTACK_ID" && \
export AGENT_BROWSER_PROFILE="$HOME/.agent-browser/profiles/riptide-$DEVSTACK_ID" && \
test -n "$DEVSTACK_LOCAL_USER_EMAIL" && test -n "$DEVSTACK_LOCAL_USER_PASSWORD"

Source `.env` rather than extracting values with `grep` and `cut`. Shell parsing removes valid wrapping quotes; text extraction keeps those quotes and sends them as part of the credential.

Snapshot the login page before entering credentials. WorkOS can show the fields on one screen or ask for email first and password second. Use labels and roles instead of refs after entering the email so later snapshots do not print it:

set -a
source .env
set +a
DEVSTACK_STATUS="$(bun --bun run devstack status --json)" && \
export DEVSTACK_ID="$(jq -r '.id' <<<"$DEVSTACK_STATUS")" && \
export AGENT_BROWSER_SESSION="riptide-$DEVSTACK_ID" && \
export AGENT_BROWSER_PROFILE="$HOME/.agent-browser/profiles/riptide-$DEVSTACK_ID" && \
test -n "$DEVSTACK_LOCAL_USER_EMAIL" && test -n "$DEVSTACK_LOCAL_USER_PASSWORD" && \
agent-browser find label "Email" fill "$DEVSTACK_LOCAL_USER_EMAIL"
agent-browser find role button click --name "Continue with email"
agent-browser wait --url "**/password**"
agent-browser find label "Password" fill "$DEVSTACK_LOCAL_USER_PASSWORD"
agent-browser find role button click --name "Sign in"

If WorkOS asks for an organization, select the exact name shown by the `Local organization` line from `bun --bun run devstack status`. The WorkOS ID in parentheses can disambiguate matching names. Any configured sandbox or dev organization is valid; do not assume a fixed name or ID. Wait for the app URL, then snapshot the signed-in page. The shared profile keeps the resulting session for later runs. If login fails, collect the URL and browser errors, but do not snapshot or take a screenshot after entering either credential.

If either variable is missing, do not ask the user to send credentials in chat. Ask them to add the shared test account values to the root `.env`, or use the headed fallback below when the shared account itself needs repair:

DEVSTACK_STATUS="$(bun --bun run devstack status --json)" && \
export DEVSTACK_ID="$(jq -r '.id' <<<"$DEVSTACK_STATUS")" && \
export AGENT_BROWSER_SESSION="riptide-$DEVSTACK_ID" && \
export AGENT_BROWSER_PROFILE="$HOME/.agent-browser/profiles/riptide-$DEVSTACK_ID" && \
APP_URL="$(jq -r '.routes.ui' <<<"$DEVSTACK_STATUS")" && \
agent-browser close && agent-browser --headed open "$APP_URL"
# user logs in
agent-browser close
agent-browser open "$APP_URL" && agent-browser wait --load networkidle && agent-browser snapshot -i

Read [references/shared-test-user.md](references/shared-test-user.md) when setting up, rot

Read more
Ships withhumanlayer

HumanLayer runs coding agents (Claude Code, Codex, OpenCode, Pi) on your machines and lets your team steer them from one place: tasks, sessions, plans, and reviews, synced between a desktop app, a web app, and a daemon on each host. This repo holds all of it.

Get the whole plugin

Other skills on humanlayer.