# Get started

Create the first workspace and project, then run your first Playwright job.

Use this path when you are starting with an empty account. BernOps begins at the workspace level, then every automation resource lives under a project.

**The short version**

Create a workspace, connect a worker, create a project inside the workspace, add a Playwright job, then run that job and inspect the result timeline.


## Create a workspace

Open [Home](https://app.bernops.com/home) and choose **Create Workspace**. A workspace is the top-level container for your projects and future team access.

If you already have a workspace, open it from the **Your workspaces** section. The workspace page shows aggregate run health and the project portfolio for that workspace.

### Connect a worker

Click the worker cog or **Workspace > Workers** to open the [Workers page](https://app.bernops.com/workspaces/workers). An empty list is expected before enrollment; local demo tooling may already have provisioned its own worker. You do not need a project selected to add a worker.

On a supported Linux/amd64 Docker host, install the operator-approved private bootstrap using the [CLI prerequisites and installation guide](/docs/workers-and-pool#worker-setup). There is no supported public download or npm install name. Then run:

```bash
bernops setup
```

Choose **3 (automation worker)**, or **4 (both)** if you also want a personal coding agent. The menu defaults to **1 (platform authentication only)**, which installs no worker. The wizard handles platform login, checks Docker, and obtains a signed immutable worker release with the private SDK bundled, without a source checkout or manual Docker build. It verifies SDK/browser readiness before requesting separate workspace approval. Compare the computer fingerprint, choose the workspace as an owner or admin, and approve workload execution.

The CLI keeps the platform session separate from the worker's workspace-only credential; it never passes personal OAuth to the container. Wait for setup to report the worker ready with a confirmed connection, then check it on the Workers page. A running container alone is insufficient. The name defaults to the saved wizard name, otherwise the sanitized hostname; `--worker-name` is optional.

No preliminary `bernops auth login` is required: that command is **auth-only** and never enrolls a host or worker. Choose the agent in [Coding agent CLI](/docs/coding-agent-cli) for separate host approval, Codex login when needed, repository access, and user-service connection readiness. Worker-only selection configures none of those agent components.

Setup uses saved identity, then its journal, then the bootstrap default unless you pass a target explicitly. For local development, `./dev.sh install-cli` activates a local-target bootstrap, then use bare `bernops setup`; `--target local` remains available. This does not install NVM. See [Local development only](/docs/workers-and-pool#local-development) for prerequisites. Native Linux Secret Service is the local/cloud default; `--credential-store file` explicitly accepts unencrypted storage for a new identity. For remote approvals use `--no-browser`, not the agent-only `--headless` flag.

## Create a project

Inside a workspace, create a project for the application or operational surface you want to automate. Projects are the boundary for jobs, runs, variables, queues, triggers, and API keys.

Use one project per application or environment boundary. That keeps API keys and runtime variables scoped to the smallest useful surface.

## Add a Playwright job

Open the project dashboard and choose **New Job**. Paste a Playwright spec that can run from a worker without relying on local browser state.

Start with explicit checks and readable steps:

```ts
import { test, expect } from "@playwright/test";

test("home page responds", async ({ page }) => {
  await test.step("open the application", async () => {
    await page.goto(process.env.BASE_URL ?? "https://example.com");
  });

  await test.step("verify the page loaded", async () => {
    await expect(page.locator("body")).toBeVisible();
  });
});
```

Use [Runtime variables](/docs/runtime-variables) when values such as `BASE_URL`, credentials, or tenant IDs should differ per project.

## Run and inspect

Run the saved job from the project dashboard. BernOps dispatches the execution to a connected worker, records logs and steps, and links to the run detail page.

If the run stays `pending`, check that a compatible worker is connected to this workspace and that [concurrency limits](/docs/workers-and-pool#concurrency-limits) allow it to start. Creating a job does not provision a worker automatically.

Use the run detail page to inspect:

- Final status and duration.
- Step timeline and log output.
- Screenshots, traces, and attachments when the job emits them.
- Network and console signal for browser-driven failures.

## Automate next

After the first manual run works, choose the automation path that matches your workflow:

- Read [Playwright jobs](/docs/playwright-jobs) to refine job structure and reports.
- Connect a computer with the [Coding agent CLI](/docs/coding-agent-cli) for creator-owned Pi sessions.
- Create [API keys](/docs/api-keys-scopes) for CI, external runners, or MCP-style agents.
- Use [Queues](/docs/queues) when jobs need to produce and consume units of work.
- Use the [API Reference](/docs/api) for endpoint schemas and try-it requests.
