

<!-- Source: .ruler/AGENTS.md -->

# Qwik v2 agents reference, instructions and rules

> [!IMPORTANT]
> **ALWAYS RUN `ruler apply` AT THE START OF A SESSION.** The agent skills are gitignored, not
> committed, so a fresh clone/worktree has none until you generate them (once per worktree):
>
> ```bash
> pnpm dlx @intellectronica/ruler@0.3.42 apply --no-gitignore --no-mcp
> ```

> Canonical source for repo-wide AI coding agent rules. For contributor setup, see
> [CONTRIBUTING.md](./CONTRIBUTING.md). For package-specific workflows, load the relevant
> `.ruler/skills/*/SKILL.md` file.

## Source Of Truth

- Shared AI guidance lives in `.ruler/`.
- Only the root `AGENTS.md` and `CLAUDE.md` are committed generated outputs; the `.claude/`/`.codex/`
  skill copies are gitignored and regenerated locally with `ruler apply` (see Setup below).
- Never hand-edit a generated output — edit `.ruler/` and regenerate with `ruler apply`. A CI check
  re-runs it and fails if the committed root files drift.
- To change assistant behavior, edit `.ruler/AGENTS.md`, `.ruler/README.md`, or `.ruler/skills/**`,
  then regenerate with Ruler when needed.

## Project Snapshot

Qwik is a resumable web framework. SSR serializes application and framework state into HTML, and
the client resumes without re-running component code. Qwik v2 is a rewrite with VNode-based
runtime work, rewritten reactive primitives, a new serialization mechanism, and package names under
`@qwik.dev/*`.

Key concepts: resumability, QRLs, `$`-suffixed optimizer boundaries, fine-grained signals, VNodes,
the cursor system, and the Rust optimizer.

## Monorepo Map

- Base branch and release branch for v2 PRs: `main`. V1 lives on the `v1` branch.

| Package | Path | Notes |
| --- | --- | --- |
| `@qwik.dev/core` | `packages/qwik` | Core runtime, SSR, optimizer-facing code |
| `@qwik.dev/router` | `packages/qwik-router` | Routing, middleware, adapters, SSG |
| `@qwik.dev/react` | `packages/qwik-react` | React integration |
| `@qwik.dev/dom` | `packages/qwik-dom` | Server-side DOM implementation |
| `@qwik.dev/qwik-vite` | `packages/qwik-vite` | `vite-plugin-qwik`, private, bundled into `@qwik.dev/core/optimizer` |
| `@qwik.dev/optimizer` | `packages/optimizer` | Rust optimizer, WASM, NAPI bindings |
| `eslint-plugin-qwik` | `packages/eslint-plugin-qwik` | ESLint rules |
| `create-qwik` | `packages/create-qwik` | Project scaffolding CLI |
| `qwik-docs` | `packages/docs` | Docs site, private package |
| `insights` | `packages/insights` | Analytics dashboard, private package |

Use v2 package names (`@qwik.dev/core`, `@qwik.dev/router`, etc.). Do not introduce v1
`@builder.io/qwik` or `@builder.io/qwik-city` imports except when working on explicit
compatibility override code.

## Setup And Iteration Loop

This is the canonical loop for nearly all framework work. Default to it; do not substitute broader
commands:

### getting started

```bash
pnpm i
```

```bash
# Materialize the agent skills into .claude/.codex (gitignored) — run once per fresh clone/worktree.
pnpm dlx @intellectronica/ruler@0.3.42 apply --no-gitignore --no-mcp
```

```bash
pnpm build.core # for a fresh start
pnpm build.full # for a fresh start and you are working on the docs (the docs run the optimizer)
```
### Iterating

Prefer focused commands and builds over repo-wide commands and builds.

```bash
# Fast dev build — required once before any tests can run, and again after framework
# source changes when the verification consumes build output (all e2e suites do)
pnpm build.core.dev

# Closest focused unit/spec test
pnpm vitest run packages/qwik/src/core/tests/use-task.spec.tsx

# Focused e2e test
pnpm playwright test e2e/qwik-e2e/tests/events.e2e.ts --browser=chromium --config e2e/qwik-e2e/playwright.config.ts
```

`build.core.dev` also re-emits fresh Qwik and Router `.d.ts` incrementally (via `tscDevDts` + re-export shims), so editing a public signature no longer leaves stale types — `build.watch` skips the type pass to stay instant.

For Qwik e2e tests, use `--browser=chromium` with `e2e/qwik-e2e/playwright.config.ts`.

Re-run `pnpm build.full` when you are touching the optimizer rust code.

### When making a PR

```bash
# for type-level verification when no focused test covers the change
pnpm tsc.check

# update the API
pnpm api.update

# Verify the build passes
pnpm build.core

# Verify unit tests pass
pnpm test.unit

# Verify the E2Es pass
pnpm test.e2e.chromium

# In case of html output change, update the ssg snapshot
pnpm test.e2e.router.ssg.update

# In case of a new feature, run the test.bench
pnpm test.bench

# In case of qwikloader changes
pnpm vitest packages/qwik/src/qwikloader.unit.ts -u
```

If any of those fail, fix and push your changes.

## Rules

Recent Qwik v2 work by core maintainers favors small, behavior-shaped changes with regression proof.
Follow that bias:

### Guidance Freshness

- If a skill or reference you used is stale, incomplete, or contradicted by current source, update
  the `.ruler` source guidance before finishing the task unless the user explicitly restricted the
  scope.
- Keep new durable lessons in the most specific skill or reference that future agents are likely to
  load. Do not add package-specific details to these always-on rules unless they affect most tasks.
- Only add a lesson to a skill when it generalizes to future tasks. Keep single-PR specifics (one
  module's protocol, one fix's mechanics) in the code and its tests, not in a skill.
- Write those notes **prescriptively** — the invariants to keep, the traps that cause false passes,
  where things live, and how to verify — rather than describing how the code currently works. Omit "don't do X" prohibitions for anything a test already enforces; the
  suite is the guardrail, so reserve notes for what it can't self-enforce.
- When updating guidance, load the `qwik-guidance-maintenance` skill.

### Skill Selection

Load the relevant skill before non-trivial work in that area:

| Skill | Use when |
| --- | --- |
| `qwik-core-development` | Editing/reviewing `packages/qwik/**` core runtime code |
| `qwik-router-development` | Editing/reviewing router runtime, buildtime, middleware, adapters, or SSG |
| `qwik-optimizer-development` | Editing/reviewing Rust optimizer, WASM, NAPI, or optimizer-facing behavior |
| `qwik-e2e-verification` | Creating, debugging, or running Playwright e2e suites |
| `qwik-docs-development` | Writing/editing docs content, docs site routes, or docs LLM outputs |
| `qwik-guidance-maintenance` | Editing `.ruler/**`, generated-output guidance, or stale skill/reference content |

If no skill fits, stay with these repo-wide rules and inspect local source before changing code.

If a skill above is not loadable, its copy has not been generated in this worktree yet — run the
`ruler apply` step from Setup, or read the source directly at `.ruler/skills/<name>/SKILL.md`.

Keep the `qwik-` prefix on committed source skill names. Ruler copies these skills into
agent-native skill directories where they may coexist with user or plugin skills, so the prefix keeps
the skill list unambiguous outside the repo-local `.ruler` tree.

### Changesets

When a change affects published packages, add a changeset under `.changeset/`.

- Use `patch` for bug fixes: focus on the issue rather than the solution.
- `minor` for new features: explain the new feature.
- `major` for API removal: may also include a new feature, but it must remove or break a public API.
- Enforce 1 changeset per change.
- Write the changeset summary in lowercase (e.g. `fix:`)
- 1 short sentence (10-ish words) focused on the bug fix or feature. Don't include implementation details.

### Code Quality


#### Sanity

- Remember to keep your code DRY.
- Do not leave debug logging or temporary names in the final diff.
- Only add comments for crucial information that is not self-explanatory. Keep your comments constrained to 1 short sentence (10-ish words) maximum. Focus on explaning the why/issue rather than implementation details.  
- Write one changeset per patch/minor/major change. Keep the changeset message constrained to 1 short sentence or 2 maximum, focused on the bug fix, feature or breaking changes. Don't explain the internals or implementation details.

#### Naming

- Use names that explain the domain idea, not the implementation trick.
- Prefer specific names over short names when the value crosses more than a few lines.
- Name booleans as questions or states, such as `isReady`, `hasSubscribers`, or `shouldFlush`.
- Name functions by the action they perform, such as `resolveLoaderData()` or
  `markContainerReady()`.
- Avoid vague names like `data`, `item`, `temp`, `handle`, `process`, or `doWork` unless the local
  scope makes the meaning obvious.
- Keep existing public API names unless the task is intentionally changing the API.

#### Control Flow

- Prefer early returns for invalid, empty, unsupported, or already-handled cases.
- Avoid deep nesting when a guard clause can make the main path easier to read.
- Keep the success path visible at the outer indentation level when possible.
- Do not use clever boolean expressions when a named condition or small helper would be clearer.
- Keep error and compatibility branches explicit so reviewers can see why they exist.

#### Modularity

- Keep functions focused on one responsibility.
- Extract a helper when a block has a clear name, is reused, or hides the main path.
- Do not extract helpers only to move complexity around; the caller should become easier to read.
- Keep helpers close to their first use unless they are shared across files.
- Prefer local semantic helpers over broad abstractions.
- Keep consumer- or framework-specific carve-outs (magic values, special cases) at the boundary that
  owns that knowledge; do not push them into a generic lower-level utility that should stay agnostic.

#### Review Standard

Before finishing, read the changed code as if you are new to the package:

1. Can a junior developer explain what each name represents?
2. Can an AI agent identify the main path without following deeply nested branches?
3. Are edge cases handled by clear guard clauses or named helpers?
4. Is the change modular without hiding important state or protocol boundaries?

If the answer is no, simplify the code before calling the task complete.

### Code Style

Prettier and ESLint define style. Keep semicolons, single quotes, two-space indentation, trailing
commas where configured, and always use braces for control flow.

Naming conventions:

| Pattern | Usage |
| --- | --- |
| `use*` | Hooks called in component/task scope |
| `*$` | QRL boundary extracted by the optimizer |
| `create*` | Factory functions |
| `*.unit.ts(x)` | Vitest unit files |
| `*.spec.ts(x)` | Vitest spec files |
| `*.e2e.ts` | Playwright e2e files |

### Security And Supply Chain

Treat security-sensitive changes as behavior changes even when they look like config, dependency,
or CI maintenance.

#### Security Review Trigger

Pause for a focused security pass when a change touches:

- authentication, authorization, sessions, cookies, redirects, URL parsing, filesystem paths, SSR,
  serialization, HTML/script output, request handling, or server adapters
- dependency versions, lockfiles, package manager settings, release scripts, publishing scripts, or
  build tooling
- GitHub Actions, reusable workflows, workflow permissions, tokens, secrets, cache keys, artifact
  upload/download, or deployment credentials

Use the changed diff as the starting point. Check directly supporting files when needed, but do not
turn a small change into a repository-wide security scan unless the user asks.

#### What To Check

- Identify the trust boundary: attacker-controlled input, untrusted dependency code, untrusted CI
  event data, secrets, tokens, publish credentials, or generated output.
- Find the closest existing guard and the sink it protects. Do not claim safety from a broad
  intuition; point to the concrete validation, escaping, permission, or isolation boundary.
- Prefer fail-closed behavior for malformed input, unknown modes, unsupported hosts, and missing
  config.
- Keep secrets out of logs, snapshots, artifacts, caches, generated files, browser output, and error
  messages.
- When changing dependencies or build tools, check for new install scripts, binary downloads,
  network fetches, transitive tool execution, license or provenance surprises, and lockfile drift.

#### GitHub Actions

When editing `.github/workflows/**` or action-related scripts:

- Keep `permissions:` least-privilege at the workflow or job level.
- Do not introduce `pull_request_target` for code checkout/build/test of untrusted PR content unless
  the workflow is explicitly designed to avoid running attacker-controlled code with secrets.
- Avoid passing secrets to forked PRs, third-party actions, shell commands that print env, or
  generated artifacts.
- Prefer trusted first-party actions. For new third-party actions, pin to a full commit SHA or
  document why a moving tag is acceptable.
- Treat cache restore keys and artifact paths as untrusted input surfaces. Avoid broad paths that can
  poison future jobs or expose credentials.
- Quote shell variables and avoid `eval`, curl-piped shells, and unchecked interpolation of GitHub
  context values into shell commands.

#### Verification

For security-sensitive changes, record the focused security reasoning in the final response:

1. What boundary changed?
2. What guard or invariant prevents abuse?
3. What focused test, lint, config check, or manual inspection covered it?

If you cannot verify the security property locally, say exactly what remains unverified.

### Test Driven Development

Use test-driven development for behavior changes and bug fixes.

#### Required Workflow

1. Identify the observable behavior or invariant before editing implementation code.
2. Add or update the closest focused test that proves the behavior.
3. Run that test before the implementation change when feasible and confirm it fails for the
   expected reason.
4. Make the smallest implementation change that satisfies the test.
5. Rerun the focused test and keep iterating until it passes.
6. Run any broader verification required by the touched surface, such as API docs, optimizer
   snapshots, build output, or e2e coverage.

#### Test Selection

- Prefer unit/spec tests next to the changed code.
- Use optimizer fixtures and snapshots for Rust transform behavior.
- Use e2e tests only when the behavior depends on a real browser, navigation, streaming, SSR/CSR
  integration, adapter behavior, or fixture app wiring.
- For serialization, hydration, streaming, or loader protocol changes, test both the writer and the
  reader path.
- For compatibility behavior, test both the current API path and the supported deprecated path.

#### Exceptions

Docs-only, rules-only, formatting-only, dependency metadata, and generated-output maintenance
changes do not need a failing product test first. They still need the narrowest relevant
verification, such as formatting, Ruler dry-run, generated-output checks, or docs build checks.

If dependencies, missing generated artifacts, or local environment constraints prevent a pre-fix
test run, write the focused test first, record the blocker, and run the test as soon as the blocker
is resolved.

### Boundaries

- Preserve user work and unrelated changes. Do not reset or revert unrelated files.
- Keep edits scoped to the package, generated-file boundary, and verification surface implied by the
  task.
- Do not commit `.only` tests.
- Do not skip tests for behavior changes; use the closest focused test first.

### No Hydration Terminology

Never describe Qwik or any part of how Qwik works as hydration. Qwik does not hydrate. Qwik is
resumable: the server serializes application state and listeners into the HTML, and the client
resumes execution exactly where the server left off, without re-running component code or
rebuilding the framework state.

- Do not call any Qwik mechanism "hydration", "hydrating", "rehydration", "partial hydration",
  "progressive hydration", "selective hydration", or "island hydration".
- Do not describe Qwik components, containers, or apps as "hydrated" or "needing to hydrate".
- Use the Qwik terminilogy instead: "javascript streaming", "JIT preloading", "resumability", "resume", "resuming", "serialization", "deserialization", and "lazy execution".
- Describe client startup as Qwik resuming from serialized state, not as Qwik booting, mounting,
  or hydrating the app.

#### Allowed Mentions

The word "hydration" may appear only when explicitly contrasting Qwik with hydration-based
frameworks, and the sentence must make clear that hydration is what other frameworks do and what
Qwik avoids. For example: "Unlike frameworks that hydrate on the client, Qwik resumes from
serialized state." Never use hydration vocabulary, even casually or by analogy, to explain what
Qwik itself does.



<!-- Source: .ruler/README.md -->

# Ruler Setup

This project uses [Ruler](https://github.com/intellectronica/ruler) to keep AI assistant instructions in one committed source of truth.

## Source Of Truth

```
.ruler/
├── AGENTS.md      # Repo-wide guidance + always-on rules (appended at the end)
├── skills/        # Shared source skills propagated by Ruler
└── ruler.toml     # Ruler agent configuration
```

Use `.ruler/AGENTS.md` for always-on repository context and rules (the rules live as sections at the
end of that file). Use `.ruler/skills/` for task-specific workflows that should be loaded only when
relevant.

Always-on rules currently in `.ruler/AGENTS.md`:

- `changeset-conventions`
- `code-quality`
- `generated-output-boundaries`
- `guidance-source-of-truth`
- `no-hydration-terminology`
- `security-and-supply-chain`
- `test-driven-development`

Current source skills:

- `qwik-core-development`
- `qwik-router-development`
- `qwik-optimizer-development`
- `qwik-e2e-verification`
- `qwik-docs-development`
- `qwik-guidance-maintenance`

The `qwik-` prefix is intentional. Ruler copies skills into assistant-native directories where they
can appear beside personal and plugin skills, so the prefix keeps these repo skills recognizable
outside the `.ruler/` tree.

Root `AGENTS.md` and `CLAUDE.md` are generated by Ruler but committed (so fresh clones and worktrees
have the always-on guidance immediately). The generated skill directories (`.claude/skills/`,
`.codex/skills/`) and the rest of `.claude/`/`.codex/`/`.cursor/` stay local and gitignored — run
`ruler apply` to materialize the skills. Never edit a generated file directly — update `.ruler/`,
run `ruler apply`, and commit the regenerated root files.

## AI Config Builder

Treat Ruler as the source layer and the selected assistant as the output layer.

When you are setting up or debugging an assistant-specific config:

1. Identify the target assistant and Ruler agent id.
2. Read this file and `.ruler/ruler.toml`.
3. Research the target assistant's current native instruction, rule, skill, config, and policy
   formats when the mapping is ambiguous.
4. Map `.ruler` files by semantic role, not by filename.
5. Run `ruler apply --agents <agent>`.
6. Verify that the generated files contain the expected source guidance and skills.

| Ruler source | Semantic role | Builder action |
| --- | --- | --- |
| `.ruler/AGENTS.md` | Repo-wide AI guidance + always-on rules | Generate into the target assistant's primary native guidance file. |
| `.ruler/skills/*/SKILL.md` | Task-triggered workflows | Copy to the target assistant's native skills directory when supported. |
| `.ruler/ruler.toml` and Ruler MCP config | Agent selection, output paths, MCP/config | Generate or merge native config only where Ruler and the target assistant support it. |

Different tools use words like "rules" for different things. A native rules file may mean
natural-language guidance, directory-scoped steering, MCP config, hooks, or command execution
policy. Check current docs or the installed Ruler adapter before creating or copying a tool-specific
file.

## Markdown Guidance Bundle

The AI-agnostic Markdown guidance bundle is `.ruler/AGENTS.md` (repo-wide context plus the always-on
rules appended at its end) together with this `.ruler/README.md`.

Ruler concatenates that bundle and writes it to each selected assistant's native AI guidance file.
Use source markers in the generated file to verify inclusion. Do not bypass Ruler by copying these
Markdown files into a tool-specific directory whose format has not been verified.

If you are an AI assistant building local config for a target tool, research that tool's current
native guidance, skill, config, and policy formats before adding any tool-specific output. Map
`.ruler` files by what they mean, not by filename: Markdown guidance belongs in the assistant's
native AI guidance surface, skills belong in native skills if supported, and command-permission
policy belongs only in a separately researched policy format. For Codex, Ruler includes all
`.ruler` Markdown guidance in generated `AGENTS.md`; `.codex/rules/*.rules` is command policy, not
Markdown guidance.

### Worked Example: Codex

Current Ruler and OpenAI Codex behavior maps this repo's sources as follows:

| Ruler source | Codex-native output | Verify after `ruler apply --agents codex` |
| --- | --- | --- |
| `.ruler/AGENTS.md` | Generated root `AGENTS.md` | `rg -n 'Source: .ruler/AGENTS.md' AGENTS.md` |
| `.ruler/skills/*/SKILL.md` | `.codex/skills/*/SKILL.md` | `find .codex/skills -name SKILL.md` |
| Ruler MCP config | `.codex/config.toml` when MCP config is generated | `test -f .codex/config.toml` when MCP/config is expected |

Codex `.rules` files are command execution policy files that use `prefix_rule(...)`. They are not a
target for `.ruler/AGENTS.md` prose guidance. If Codex command policy is needed, maintain it as a
separate local or team policy using OpenAI Codex's `.rules` format; do not treat it as Ruler
Markdown guidance.

Expected Codex check:

```bash
ruler apply --agents codex
rg -n 'Source: .ruler/AGENTS.md' AGENTS.md
find .codex/skills -name SKILL.md
```

## What Is Committed vs Regenerated

Only the root `AGENTS.md` and `CLAUDE.md` are **committed** generated outputs, so a fresh clone or
worktree has the always-on guidance immediately (`.ruler/ruler.toml` keeps `[gitignore] enabled = false`
so Ruler leaves those two files tracked). The generated skill copies (`.claude/skills/`,
`.codex/skills/`) are **gitignored** — regenerate them locally with `ruler apply`. This keeps skill
and note edits from appearing three times (source plus two copies) in every PR.

To change guidance, edit `.ruler/`, run `ruler apply`, and commit the regenerated root files
alongside your `.ruler/` change. Never hand-edit the generated files. A CI check
(`.github/workflows/ruler-check.yml`) re-runs `ruler apply` and fails if the committed root files
drift from `.ruler/`.

## Generate Local Assistant Files

Install Ruler if you do not already have it:

```bash
npm install -g @intellectronica/ruler
```

Or run it without installing (the form used by fresh worktrees and CI):

```bash
pnpm dlx @intellectronica/ruler@0.3.42 apply --no-gitignore --no-mcp
```

Generate files for the default configured agents:

```bash
ruler apply
```

Generate files for a specific assistant:

```bash
ruler apply --agents claude
ruler apply --agents codex
```

Generate files for multiple assistants:

```bash
ruler apply --agents claude,codex
```

## Project And Personal Configuration

Use `.ruler/` for team-shared instructions and project conventions that should travel with the repo.

Use `~/.config/ruler/` for personal preferences, local workflow shortcuts, API keys, and personal MCP servers:

```bash
ruler init --global
```

If it helps everyone working in this repo, add it to `.ruler/`. If it only helps your local setup,
keep it in your global Ruler config.

## Updating Instructions

Edit `.ruler/AGENTS.md` for repository-wide guidance and always-on rules (the rules are sections at
the end of that file). Edit the relevant `.ruler/skills/<skill-name>/SKILL.md` file for
package-specific or workflow-specific guidance.

If a code task proves a skill or reference stale, update that guidance as part of the same task when
the scope allows it.

Then regenerate the local assistant files:

```bash
ruler apply --agents <your-tool>
```

Do not update generated files like `CLAUDE.md` or `AGENTS.md` by hand. They will be overwritten the
next time Ruler runs.

## Skills

Author shared skills under `.ruler/skills/` (the committed source). Ruler copies them into each
enabled agent's skill directory (`.claude/skills/` for Claude, `.codex/skills/` for Codex); those
copies are gitignored, so run `ruler apply` once per fresh clone or worktree to materialize them.
Never hand-edit the copies — edit `.ruler/skills/` and regenerate.

Keep each skill focused:

- Use frontmatter with `name` and a trigger-oriented `description`.
- Put the fast path in `SKILL.md`.
- Move long notes into `references/` only when progressive disclosure helps.
- Keep always-on policy in `.ruler/AGENTS.md`, not duplicated in every skill.
- Keep durable maintainer lessons current. Prefer updating the specific skill/reference that was
  wrong over adding broad prose here.
