Immutable. This exact content is served forever at /api/v1/blob/0befabd92d83be24.
---
name: unikit-rules
description: >-
Add a short, project-specific rule, convention, or override to .unikit/RULES.md — the
quick-capture inbox for this project's rules; each invocation appends a rule,
automatically loaded by /unikit-implement before execution (later promotable into the
knowledge base via /unikit-memory migrate-rules). Works only with a rule typed as a
prompt — it does NOT read files, folders, URLs, or PDFs. Cross-checks against the
knowledge base (RULES_INDEX.md) to avoid duplicating core/stack entries. Use for fast,
one-line conventions and corrections: "add a rule", "remember this", "convention",
"always do X", "never use Y", "from now on do Z", or when the user corrects agent
behavior and wants it remembered. If the user points to a source (file, folder, URL,
PDF, article, book) or wants to research/document framework usage, use /unikit-memory;
for architecture decisions use ARCHITECTURE.md.
argument-hint: "[rule text or topic | numbered batch]"
allowed-tools:
- Read
- Write
- Edit
- Glob
- Grep
---
# UniKit Rules — Project Conventions
Add short, actionable rules to `.unikit/RULES.md`. Rules are project-specific overrides that take precedence over the base knowledge rules in `.unikit/memory/code/core/` and `.unikit/memory/code/stack/`.
Before adding any rule, cross-check it against RULES_INDEX.md to avoid duplicating what's already covered in the knowledge base. If a rule is already covered — tell the user and skip. If the rule contradicts or extends an existing knowledge base rule — add it as an explicit override to RULES.md with a note about what it overrides.
## Language Awareness — BLOCKING PRE-REQUISITE
**BEFORE producing ANY output**, silently read `.unikit/system/LANGUAGE_RULES.md`
and apply its rules to ALL subsequent output.
If the file is missing or unreadable, fall back to English.
Do not produce any user-facing output until language rules are loaded.
Do not announce, confirm, or mention the language setting.
Skill-specific rule:
- If the user provides a rule in a non-English language, translate it to English before writing to `.unikit/RULES.md`
## Workflow
### Step 0: Load Skill Context
Read `.unikit/skill-context/unikit-rules/SKILL.md` if it exists. Treat it as project-level overrides — when it conflicts with this SKILL.md, the skill-context wins.
### Step 1: Determine Mode
```
Check $ARGUMENTS:
├── Numbered batch? → Mode A: Direct add, N rules
├── Has text? → Mode A: Direct add, 1 rule
└── No arguments? → Mode B: Interactive
```
**Mode A** — user provided rule text:
```
/unikit-rules Never use var, always explicit types
```
→ Proceed to Step 2 with the provided text.
**Mode A, batch form** — the argument carries several rules at once. It is a **numbered
batch** when two or more lines begin with `^\d+\. ` at column zero. Each rule starts at
such a marker and runs to the next one, or to the end of the input:
```
/unikit-rules 1. Constructor null checks MUST be symmetric across injected dependencies.
2. Event subscriptions go before any fallible operation in OnInit; unsubscribe in OnExit
even when OnInit threw.
3. Never call DiResolver.Resolve<T>() without a null guard — throw, do not warn.
```
Why the numeral and not a newline or a `- ` bullet: Step 4 allows a single rule to span
multiple lines (a table, a code block), so a bare line break does not separate two rules,
and `- ` is the element format of `RULES.md` itself and appears **inside** a rule. A
numbered element never does, so `^\d+\. ` at column zero cannot collide with content.
Run Steps 2-5 per rule and report all of them together in Step 6. One rule and N rules
differ only in how many rows the report carries.
**Mode B** — no arguments:
→ Ask the user what rule to add. Offer examples relevant to {{engine_name}}/{{engine_code_language}}:
```
What rule or convention would you like to add?
Examples:
- Never use var — always declare explicit types
- MonoBehaviour injection via public Construct() with [Inject]
- All async methods must accept CancellationToken as last parameter
- Use canvas.enabled instead of SetActive for UI toggling
- Factory classes instead of Zenject PlaceholderFactory
```
### Step 2: Cross-Check Against Knowledge Base
This step prevents duplication and helps maintain a clean separation between project rules and knowledge base rules.
1. **Read `.unikit/memory/code/RULES_INDEX.md`** — get the list of all rule files with their descriptions and "Load When" hints.
2. **Identify potentially overlapping rule files** — based on the topic of the new rule, find rule files from the index that cover the same area. For example:
- Rule about naming → check `code-style.md`
- Rule about async/UniTask → check `reactive-async.md`
- Rule about Zenject → likely already in `RULES.md` (Zenject DI section) or `design-principles.md`
- Rule about Odin attributes → check `odin.md`
3. **Read the relevant rule file(s)** — only the ones that might overlap (not all of them).
4. **Determine the relationship:**
| Situation | Action |
|-----------|--------|
| Rule already exists with the same meaning | Tell user: "This is already covered in `{file}`: {quote}". Skip. |
| Rule contradicts an existing knowledge base rule | Add to RULES.md with override note. Tell user what it overrides. |
| Rule extends/narrows an existing rule | Add to RULES.md. Mention the related base rule for context. |
| Rule covers a new topic not in knowledge base | Add to RULES.md. |
### Step 3: Read or Create RULES.md
Check if `.unikit/RULES.md` exists.
**If it does NOT exist** → create it:
```markdown
# Project Rules
Project-specific rules that override or extend the base knowledge rules in `.unikit/memory/`.
For base code style see `rules/core/code-style.md`.
---
## General
- [new rule here]
```
**If it exists** → read it, find the appropriate section for the new rule.
### Step 4: Place Rule in the Right Section
RULES.md is organized by topic sections (e.g., `## Type Declarations`, `## Conditions`, `## Zenject DI`). Place the new rule under the section that best matches its topic.
**If a matching section exists** → append the rule at the end of that section as a `- ` list item.
**If no matching section exists** → create a new `## Section` before the last section in the file, then add the rule there. Choose a clear, short section name that describes the topic (e.g., `## Async Patterns`, `## UI Conventions`, `## Testing`).
**Formatting rules:**
- Each rule is a `- ` list item (can span multiple lines for tables/code blocks if needed)
- Keep rules short and actionable — directive language ("Never...", "Always...", "Use...")
- No duplicates — if a rule with the same meaning already exists in RULES.md, tell user and skip
- If user provides multiple rules at once, add each to its appropriate section
### Step 5: Also Check Existing RULES.md
Before writing, verify the new rule doesn't duplicate something already in RULES.md itself (not just the knowledge base). Read through existing rules and check for semantic overlap.
### Step 6: Write and Confirm
Use `Edit` to add the rule(s). Then report — **one row per input rule, skipped ones
included**:
```markdown
## Batch result — N rules
| # | Outcome | Section | Cross-check |
|---|---------|---------|-------------|
| 1 | added | Async Patterns | no overlap |
| 2 | already-covered | — | core/reactive-async.md |
| 3 | added | Zenject DI | extends code-style.md |
| 4 | skipped-duplicate | Conditions | same meaning as existing entry |
```
Outcomes, and nothing else:
- `added` — written into `.unikit/RULES.md`, `Section` names where
- `already-covered` — the knowledge base already carries it (Step 2); `Cross-check` names the file
- `skipped-duplicate` — `RULES.md` already carries the same meaning (Step 5)
**A rule with no row in the report was not processed.** That is the fourth outcome, and it
is expressed by absence rather than by a token because absence is how it actually happens —
a run that ends early leaves no row to write.
**A batch is not atomic: a partial write is a normal outcome, and the report is the only
way to learn which part landed.** Do not roll back written rules because a later one
failed, and do not suppress the table when only some rules were processed.
A single-rule call renders the same table with one row. There is no second format.
The `Section` column is not decoration: a caller writing its own log records which section
each rule landed in, and in a batch there is nowhere else to read it from.
If the input looked like a numbered batch but parsed as one rule, say so in the report
instead of silently writing the whole text as a single `RULES.md` entry.
## Priority Reminder
From RULES_INDEX.md, the override priority (highest wins):
1. `.unikit/RULES.md` — project-specific overrides (what this skill writes to)
2. `.unikit/ARCHITECTURE.md` — project architecture decisions
3. `.unikit/memory/code/core/*.md` — universal best practices
4. `.unikit/memory/code/stack/*.md` — framework-specific knowledge
Rules added by this skill have the highest priority and override everything below them. This is by design — project rules exist precisely to override defaults when the project needs something different.