Project-wide rules for any AI coding agent working in this repo (Claude Code, Cursor, Codex, etc.). The canonical project conventions live in .claude/skills.md; the per-task playbooks live in .claude/skills/<name>/skill.md. This file is the rules-of-engagement layer on top of those.
- Keep answers short and concise.
- No emojis in commits, issues, PR comments, or code.
- No fluff, cheerful filler, or congratulatory text.
- Technical prose only; be kind but direct (e.g. "Thanks @user" not "Thanks so much @user!").
- No backwards-compatibility shims unless the user explicitly asks.
- Always ask before removing functionality or code that appears intentional, even if it looks dead.
- Never disable lints or hide warnings to make a build pass — fix the underlying issue, or surface it.
- Never hardcode default ports (
1883,8883,8083,18083,3039) inside business logic. Use the broker config / Vite env / shared constants. - No secrets in code. Default
admin/publicis for local dev only.
- Block comments only —
/* */, never//or///. Project rule. - No
.unwrap()onOption::Nonepaths — particularly aroundpacket_idfor QoS 1/2. Useok_or(...)/if let Some(...). The2f10d8dcommit exists because this rule was violated. - No blocking syscalls in
asyncfunctions (std::fs,std::thread::sleep, long-heldstd::sync::Mutex). Usetokio::*equivalents. - Bounded channels (
mpsc::channel(N)) on hot paths (publish, connect).unbounded_channel()is reserved for control-plane signals only. - Every
AdminCommandmatch arm in the engine MUST send on itsoneshot::Sender, including error paths. A dropped sender hangs the controller until timeout. - Never hold a
DashMap::iter()guard across an.awaitpoint. Collect keys, drop the iterator, then await. WriteTransactionmust always end intxn.commit()?. Uncommitted txns silently roll back.
typeoverinterface. The only exception isextend-theme-types.d.ts(MUI module augmentation requiresinterface).export default function ComponentName()for all pages and section components.- JSDoc-only comments (
/** */). No//, no non-JSDoc/* */. - Single quotes everywhere (enforced by prettier).
- No
any. Checknode_modulesfor upstream types instead of guessing. - No hardcoded colors in
sx— always theme tokens. Documented exception: drawerbgcolor: '#131825'. - Responsive padding always:
sx={{ p: { xs: 2, sm: 3 } }}. - Pages are thin wrappers (import view + render). Logic lives in
sections/<feature>/<feature>_view.tsx. - Zustand stores: split
State(data) andActions(functions), sharedinitialStateconstant, mandatoryreset: () => set(initialState)for logout cleanup. Subscribe via selectors, not full destructure. - Never call
localStoragefor auth — the axios interceptor owns token refresh. - Every user-facing string is
t('key'), and every key must exist in all three ofclient/src/118n/{en,ko,uz}.json. Missing one is a bug, not a nit.
Cargo.lock— committed on purpose (binary crate). Don't.gitignoreit.client/yarn.lock— frontend uses yarn (per Makefile). Don't switch tonpm install; it produces a different lockfile and CI may break..claude/skills/code-review/references/gotchas.md— the canonical pitfall list. When you discover a new gotcha, add an entry there, don't bury it in a PR description.
After code changes, run the appropriate verification suite. Get full output, no tail. Fix all errors, warnings, and infos before committing.
| What changed | Run |
|---|---|
| Rust (server) | cargo check -p coremq-server && cargo clippy -p coremq-server --all-targets -- -D warnings && cargo fmt -p coremq-server -- --check |
| Frontend (client) | cd client && npx eslint "src/**/*.{js,jsx,ts,tsx}" && npx prettier --check "src/**/*.{ts,tsx}" |
| Both | Run the full skill: see .claude/skills/verify/skill.md |
| You wrote/changed Rust tests | cargo test -p coremq-server <test_name> and iterate until green |
| You wrote/changed integration | Tests live in tests/. Run them from the workspace root: cargo test --test <name> |
make dev— long-running, holds two servers. Only the user starts this.make server/cargo run -p coremq-server— long-running broker. Same rule.cd client && yarn dev— long-running. Same rule.
If you need to verify behavior end-to-end, ask the user to start the broker / dev server, then drive REST calls with curl or hit the dashboard manually.
cargo fmt -p coremq-server— formattingcd client && npx prettier --write "src/**/*.{ts,tsx}"— frontend formattingcd client && npm run lint:fix— eslint auto-fixable rules
Before starting work, consult the relevant skill. Each one is self-contained and references .claude/skills.md for deeper convention details.
| Skill | When to use |
|---|---|
.claude/skills/coremq-guide/ |
Project layout, ports, build commands — orientation for new tasks |
.claude/skills/code-review/ |
Reviewing changes against project conventions before committing or pushing |
.claude/skills/verify/ |
Pre-commit / pre-push verification suite (cargo + eslint + prettier) |
.claude/skills/debug-coremq/ |
Diagnosing broker, REST, MQTT, or dashboard issues |
.claude/skills/new-backend-feature/ |
Scaffolding a new admin feature through the AdminCommand pattern |
.claude/skills/web-page/ |
Scaffolding a new dashboard page / section / store |
.claude/skills.md |
Canonical CoreMQ conventions (Rust + React, API, theme, i18n) |
- Analyze PRs without pulling locally first (
gh pr view,gh pr diff). - The
.github/workflows/claude-code-review.ymlworkflow auto-reviews every PR push within a 4000-line budget. Do not duplicate that review by hand unless the user asks. - Tagging
@claudein a PR or issue comment triggers.github/workflows/claude.ymlfor targeted asks. Use it for follow-ups, not for the initial review. - If the user approves changes: create a feature branch, pull the PR's branch, rebase on
main, apply adjustments, run the verify skill, commit, merge intomain, push, close the PR with a short comment. - You never open PRs unprompted. Work on a feature branch until it matches user requirements, then merge into
mainand push.
- Write the full comment to a temp file, then
gh issue comment --body-fileorgh pr comment --body-file. Never pass multi-line markdown directly via--body. - Preview the exact comment before posting.
- Post exactly one final comment unless the user asks for multiple.
- If a comment is malformed, delete it immediately, then post one corrected comment.
- Keep comments concise, technical, and in the user's tone.
When closing an issue via commit, include fixes #<number> or closes #<number> in the commit message.
Existing branches follow short, descriptive kebab-case names that hint at the change class (e.g. fix-panic_id-none-server-panic-bug, feat-topic-new). Match this pattern:
fix-<short-slug>for bug fixesfeat-<short-slug>for new featuresrefactor-<short-slug>for non-behavioral cleanupchore-<short-slug>for tooling / docs
Existing history uses Conventional Commits prefixes:
feat:new featurefix:bug fixchore:tooling, deps, docsrefactor:non-behavioral cleanup
Format: <type>: <short imperative summary>. Body (optional) explains the why, not the what. If an issue or PR is closed by the commit, append fixes #<number> or closes #<number> on its own line.
Multiple agents may operate on different files in the same worktree simultaneously. Follow these rules without exception.
- ONLY commit files YOU changed in THIS session.
- ALWAYS include
fixes #<number>orcloses #<number>when there is a related issue or PR. - NEVER use
git add -Aorgit add .— they sweep up changes from other agents. - ALWAYS use
git add <specific-file-paths>listing only files you modified. - Before committing, run
git statusand verify only YOUR files are staged. - Track which files you created / modified / deleted during the session.
These commands can destroy other agents' work:
git reset --hard— destroys uncommitted changesgit checkout ./git restore .— destroys uncommitted changesgit clean -fd— deletes untracked filesgit stash— stashes ALL changes including other agents' workgit add -A/git add .— stages other agents' uncommitted workgit commit --no-verify— bypasses required checks; never allowed
# 1. Check status first
git status
# 2. Add ONLY your specific files
git add server/coremq-server/src/services/topic.rs
git add client/src/sections/topics/topics_view.tsx
# 3. Commit (Conventional Commits)
git commit -m "fix(server): assign packet_id for QoS 1/2 publishes"
# 4. Push (pull --rebase if needed, NEVER reset/checkout)
git pull --rebase && git push- Resolve conflicts in YOUR files only.
- If a conflict appears in a file you didn't modify, abort and ask the user.
- NEVER force push.
If user instructions conflict with the rules above, ask for explicit confirmation that the user wants to override. Only then proceed.