Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 0 additions & 56 deletions .agents/AGENTS.md

This file was deleted.

81 changes: 81 additions & 0 deletions .agents/rules/workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Workspace rules for agents that read `.agents/rules/`

These project-level rules govern all operations inside this workspace. Antigravity loads every markdown file in `.agents/rules/`; the repo-root `AGENTS.md` remains the full contract and this file does not replace it.

## Commit Per Logical Unit, Do Not Batch
- **Commit per logical unit as soon as it is complete.**
- **Push after each commit.**
- Do not batch unrelated changes into one end-of-session commit.
- A logical unit is one feature, one fix, one rename, one doc rewrite.
- Checkpoint commit triggers:
- A bug fix that produced green tests.
- A new feature that has tests passing.
- A rename or refactor that is mechanically complete.
- A doc rewrite that touches a coherent surface.
- Anything that finishes a tracked task on the TaskList.
- **Heuristic:** If more than 5 unstaged files span more than one logical concern, stop and commit the already-complete units before continuing.

## Concise by Default
- Answer directly. Skip preamble, skip restating the question, skip exhaustive analysis when a short answer suffices.
- For most questions, two to four sentences is the right length.
- If unsure whether the question needs a long or short answer, default short and offer to expand.

## Branch, Merge, and Push Guards
- **Never push to `main` / `master`.** Always push to the feature branch and create a PR via `gh pr create`.
- **Never edit or write code on `main` / `master`.** If on `main`/`master`, **STOP** and create a feature branch first (`git checkout -b feature/<name>`).
- When merging to `main`, the workflow is `gh pr create` -> confirm -> `gh pr merge`. Never do a local `git merge` + push.
- **Merge Approval:** Never merge without permission. Ask exactly: "Ready to merge `<branch>` into `<target>`? After merging, should `<branch>` be deleted or kept?" and wait for both answers.
- **Command Guard:** Ask the user before running any `git merge` command or `git push` targeting `main`/`master`.

## Commit Integrity
- **No AI attribution in commits.** Never add `Co-Authored-By: Claude`, `Generated by AI`, `AI-assisted`, or similar trailers / prefixes.
- **Imperative-mood commit subjects under 72 chars.** The body explains the reason for the change, not the diff.
- **Run tests before committing** when the project has them. Respect pre-commit hooks, do not pass `--no-verify`.

## One Task Per Git Worktree
- **One task per git worktree, ALWAYS.** There is no lone-agent exception: this repo is worked by multiple agents at once, and "no other agent is active right now" is unverifiable mid-task, since another session can start any minute. Never share one working directory across tasks.
Comment thread
vivek7405 marked this conversation as resolved.
- Two agents in one checkout collide: a `git checkout` in one moves `HEAD` under the other, so the next commit lands on the WRONG branch. Git enforces one branch per worktree, which is what makes the collision impossible.
- Give each task its own worktree:
```sh
git worktree add -b <branch> ../<repo>-<slug> origin/main
cd ../<repo>-<slug>
```
And clean it up after merge:
```sh
git worktree remove ../<repo>-<slug>
```
- Before every commit, confirm `git branch --show-current` is still the branch you created. If it moved, you are colliding with another session, so stop and move the work into its own worktree.
- The primary checkout stays an untouched mirror of `main`. Do all work in the task's worktree, never there.

## Custom Skills Usage
- These skills are symlinked into `.agents/skills/` from `.claude/skills/`, so both engines load one copy. Every entry here must have a matching symlink, and every symlink must have an entry here; `test/repo-health/agent-skill-parity.test.mjs` enforces both directions.
- `webjs-start-work`: Trigger when starting a tracked issue on the WebJs project board.
- `webjs-ready-for-dev`: Trigger when planning tracked issues into an implementable shape with verified plans.
- `webjs-file-issue`: Trigger to file a grounded issue on the board.
- `webjs-list-todos`: Trigger to check the list of TODOs.
- `webjs-research-record`: Trigger to search and record findings.
- `webjs-doc-sync`: Trigger when documenting new public surfaces or finding doc gaps or drift.
- `webjs-scaffold-sync`: Trigger when changing the CLI generators, the scaffold templates, or the agent teaching skill.
- `webjs-blog-write`: Trigger when writing, drafting, or editing a WebJs blog post under `blog/`.
- `webjs-instagram-post`: Trigger when publishing an SEO post to the WebJs Instagram account.
- `use-railway`: Trigger when interacting with Railway deploys.
- The framework teaching skill at `.agents/skills/webjs/` is a real directory rather than a symlink, and is the reference for building WebJs apps rather than a workflow trigger.
- Always use the `view_file` tool on the matched skill's `SKILL.md` before executing its tasks.

## Enforcement gates

Everything under `.claude/hooks/` fires only inside Claude Code, and that is more than the blocking gates: seven `PreToolUse` hooks that can refuse a tool call, one `UserPromptSubmit` skill router, and three `PostToolUse` hooks. None of it runs here. Two gates bind every agent regardless of engine, and neither is optional.
Comment thread
vivek7405 marked this conversation as resolved.

- `.hooks/pre-commit` runs on every commit. It blocks a direct commit to `main` or `master` and blocks a published-library version bump on any branch that is not `chore/release-*`. Never pass `git commit --no-verify`.
- `.github/workflows/ci.yml` is the test gate. Branch protection blocks a merge until the five REQUIRED checks pass: `Conventions (webjs check)`, `Unit + integration (node --test)`, `Browser (web-test-runner / Playwright)`, `E2E (Puppeteer against the blog example)`, and `Build (@webjsdev/core dist)`. The workflow defines more jobs than those five, the Bun matrix among them, so a green required set is not the same as green CI. Read every check rather than trusting the merge button to have judged for you. `.hooks/pre-commit` deliberately does not run the suite because CI does.
Comment thread
vivek7405 marked this conversation as resolved.

Because the tool-call gates do not fire here, self-check the workflow they enforce before every commit. Root `AGENTS.md` carries the full contract under Code workflow, and each gate has its own trigger conditions, so read the rules there rather than assuming a given change trips all of them. What those gates would otherwise have caught:
Comment thread
vivek7405 marked this conversation as resolved.

- Tests for every layer the change touches, staged with the change.
- The doc surfaces that change with it.
- A scaffold surface, when a feature under `packages/core`, `packages/server`, or `packages/cli` source changes what `webjs create` generates.
- A `test/bun/**` cross-runtime assertion, when the change touches a runtime-sensitive surface (the serializer, the listener and request path, SSR, action or CSRF dispatch, streams, `node:crypto`, the TypeScript stripper, auth, session, or cors).
- In an APP component, extending `WebComponent(...)` rather than raw `HTMLElement`. Framework source under `packages/` is exempt.
Comment thread
vivek7405 marked this conversation as resolved.
- One task per worktree, and invariant 11 on prose punctuation plus `WebJs` brand casing. These two bind every task and every edit.

The first four have a documented opt-out for a change that genuinely does not need them (`WEBJS_NO_TEST_GATE`, `WEBJS_NO_DOC_GATE`, `WEBJS_NO_SCAFFOLD_GATE`, `WEBJS_BUN_VERIFIED`), and root `AGENTS.md` states when each applies. Reaching for one to skip work the change actually needs is the misuse they exist despite.
Comment thread
vivek7405 marked this conversation as resolved.
1 change: 1 addition & 0 deletions .agents/skills/webjs-instagram-post
1 change: 1 addition & 0 deletions .agents/skills/webjs-ready-for-dev
1 change: 1 addition & 0 deletions .agents/skills/webjs-scaffold-sync
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ itself): commands, repo-health git config, changelog flow, dev error overlay.

## AI-driven development: guardrails for all agents

**WebJs is AI-first. These rules apply to ALL agents (Claude, Cursor, Copilot, Antigravity, Gemini, opencode) through a SINGLE cross-agent source the scaffold ships**: `AGENTS.md` (the open standard Cursor / opencode / Antigravity / the Copilot coding agent read natively) plus the skill at `.agents/skills/webjs/` and the workflow rules at `.agents/rules/workflow.md`. Tools that do not read `AGENTS.md` natively get a THIN bridge pointing at it (`CLAUDE.md` for Claude Code, `GEMINI.md` for Gemini CLI, `.github/copilot-instructions.md` for Copilot in VS Code), never a duplicated rule set. Claude Code additionally ships the protective enforcement hooks (`.claude/`, `.hooks/pre-commit`).
**WebJs is AI-first. These rules apply to ALL agents (Claude, Cursor, Copilot, Antigravity, Gemini, opencode) through a SINGLE cross-agent source the scaffold ships**: `AGENTS.md` (the open standard Cursor / opencode / Antigravity / the Copilot coding agent read natively) plus the skill at `.agents/skills/webjs/` and the workflow rules at `.agents/rules/workflow.md`. Tools that do not read `AGENTS.md` natively get a THIN bridge pointing at it (`CLAUDE.md` for Claude Code), never a duplicated rule set. The scaffold shipped `GEMINI.md` and `.github/copilot-instructions.md` as further bridges until #1368 removed them, so `CLAUDE.md` is the only one today. Claude Code additionally ships the protective enforcement hooks (`.claude/`, `.hooks/pre-commit`).

### Before starting ANY work: verify and sync the branch

Expand Down
18 changes: 9 additions & 9 deletions blog/ai-first-is-plumbing.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,13 @@ Every scaffolded WebJs app (the starter project `webjs create` generates for you
AGENTS.md agent contract (this is the load-bearing one)
CONVENTIONS.md project-specific overridable conventions
CLAUDE.md Claude Code import file (points at AGENTS.md)
.cursorrules Cursor rules (same content, different format)
.agents/skills/webjs/ the teaching skill, loaded on demand
.agents/rules/workflow.md Antigravity (Google) workspace rules
.github/copilot-instructions.md GitHub Copilot
.github/pull_request_template.md PR template (also AI-readable)
.editorconfig text-tool consistency
```

The trick is that all of them say the same thing. AGENTS.md is the source of truth; CLAUDE.md is just `@AGENTS.md` (Claude Code's import syntax). Cursor and Antigravity (formerly Windsurf) use their own formats that load equivalent content. The PR template carries the convention checklist into every code review.
The trick is that all of them say the same thing, and that there are fewer of them than there used to be. AGENTS.md is the source of truth. CLAUDE.md is just `@AGENTS.md` (Claude Code's import syntax), and it is the only bridge file left, because Cursor, opencode, Antigravity, and the Copilot coding agent all read AGENTS.md natively now. The PR template carries the convention checklist into every code review.

Most agents read whichever file matches their tool first. AGENTS.md is the cross-tool standard ([emerging spec, FYI](https://agents.md/)). Every WebJs scaffold ships it.

Expand Down Expand Up @@ -68,13 +67,12 @@ The lint is intentionally narrow. Every rule catches something that is wrong to
- `.claude/hooks/block-prose-punctuation.sh` (blocks em-dashes, pause-semicolons, and other patterns that come from training data but don't fit our docs)
- `.claude/hooks/guard-branch-context.sh` (intercepts Edit/Write when the agent is on main, forces a feature branch)
- `.claude/hooks/nudge-uncommitted.sh` (reminds the agent to commit when uncommitted-file count crosses a threshold)
- `.gemini/hooks/nudge-uncommitted.sh` (same threshold logic, Gemini CLI format)
- `.cursor/hooks/nudge-uncommitted.sh` (same, Cursor 1.7+ format)
- `.opencode/plugins/nudge-uncommitted.ts` (same, OpenCode plugin format)
- `.claude/hooks/require-tests-with-src.sh` (warns when source is staged with no test beside it)
- `.claude/hooks/check-server-imports.sh` (catches a server-only import reaching a module that ships to the browser)

Each hook is a small shell script (or TS plugin for OpenCode). They fire on the agent's tool-call events. They are advisory for everything except the branch-guard, which actively blocks edits when on main.
Each hook is a small shell script. They fire on the agent's tool-call events. They are advisory for everything except the branch-guard, which actively blocks edits when on main.

The interesting bit is that the framework ships hooks for multiple agents in the same scaffold. The agent picks the one matching its tool; the others are inert.
These are Claude-only, and that is now a deliberate choice rather than an accident of what got written first. The scaffold used to carry the same nudge logic in Gemini, Cursor, and opencode formats too. Keeping four copies of one rule in four config dialects turned out to cost more than it bought, so the scaffold dropped them and kept the two enforcement layers that bind every agent regardless of tool: the pre-commit hook above, and CI.

# WEBJS_PUBLIC_* environment shim

Expand Down Expand Up @@ -106,7 +104,9 @@ What is exciting is watching an agent take the framework as a given. No "where d

# What I am still figuring out

The hooks fragment across tools. Every new agent CLI (Cline, Codex, Factory Droid, Aider, etc.) wants its own hook format. We can ship the same content in each format via the scaffold, but maintaining six near-identical files is brittle. The longer-term answer is for AGENTS.md to become the universal contract (which is happening, slowly) and the per-tool hooks to read from it.
The hooks fragment across tools. Every new agent CLI (Cline, Codex, Factory Droid, Aider, etc.) wants its own hook format, and for a while the scaffold tried to keep up by shipping the same content in each one. That was a mistake, and I have since deleted those copies. Six near-identical files drift, and a drifted rule file is worse than a missing one, because an agent reads it and believes it. The bet now is that AGENTS.md becomes the universal contract, which is largely how it has played out, and that anything genuinely protective lives at a layer every tool has to pass through anyway. A pre-commit hook and a CI job do not care which agent wrote the code.

What I have not solved is enforcement for a tool that is not Claude Code. The blocking tool-call gates only fire there, so an agent in another editor gets the contract and the commit-time gates but not the live ones that catch a mistake as it is typed.

The other thing is the AGENTS.md size budget. We are at ~40k characters and growing. Each new feature adds a recipe, an invariant, or a doc-link. Agents have token windows that get pricey above ~50k. We are about to need a "load this section on demand" mechanism. The skill at `.agents/skills/webjs/` (SKILL.md plus its `references/`) is the start of that pattern: detail references that load only when relevant.

Expand Down
Loading
Loading