Rules
Atomic, normative rules that the ops-core resolver injects into agent context for code generation. Each file holds one rule with an ID, the archetypes it applies to, and the mechanism that enforces it. Everything else in the vault (references, patterns, research) is guidance for people and is never injected.
Decisions behind these rules are recorded in Code Generation Decisions. The human-readable package contract they derive from is Package Conventions.
Current rules
| ID | Rule | Archetypes | Severity | Core |
|---|---|---|---|---|
| STD-TS-001 | Strict compiler baseline | A7 | BLOCK | no |
| STD-TS-002 | NodeNext for Node-run code | A4, A7, A8, A14, A17 | BLOCK | yes |
| STD-TS-003 | Bundler for bundled apps | A9, A10, A11, A12, A20, A22 | BLOCK | yes |
| STD-TS-004 | Explicit exported types | A4, A7, A8 | BLOCK | yes |
| STD-TS-005 | No any, no suppression | A4, A7, A8 | BLOCK | yes |
| STD-TS-006 | Error handling by kind | A7 | ADVISORY | yes |
| STD-TS-007 | Canonical Result type | A7 | ADVISORY | yes |
| STD-PKG-001 | Zero runtime dependencies | A7 | BLOCK | yes |
| STD-PKG-002 | ESM-only manifest | A7 | ADVISORY | no |
| STD-PKG-003 | Named exports via index | A7 | BLOCK | yes |
| STD-PKG-004 | No top-level side effects | A7 | ADVISORY | yes |
| STD-PKG-005 | Never mutate inputs | A7 | ADVISORY | yes |
| STD-TOOL-001 | ESLint flat config only | all TypeScript and JS archetypes | BLOCK | no |
| STD-TOOL-002 | npm with a lockfile | A7 | BLOCK | no |
| STD-TEST-001 | Unit and acceptance layout | A7 | BLOCK | yes |
| STD-TEST-002 | Requirement-tagged tests | A7 | BLOCK | yes |
| STD-TEST-003 | Inject randomness and time | A7 | WARN | yes |
Core rules are injected for every task in a matching archetype. The others cover protected config files that agents cannot edit; the resolver adds them only when a task names them in its rules field, for example a kernel or scaffold task.
How a rule is used
- The owner commits a task file whose
vault_commitpins this vault and whoserulesfield names any extra rule IDs (CGD-09). - The ops-core resolver builds or reads the bundle for that commit and selects core rules for the target repo’s archetype, plus the named rules.
- Only the Rule, Do, Don’t and Exceptions sections are injected. Rationale and Related stay in the vault for people.
- CI records which rules were injected, so review can tell whether a failure came from the rule or from the agent.
Rule file format
Rules live in obsidian/rules/<domain>/<ID>-<slug>.md, with domains typescript (STD-TS), package (STD-PKG), testing (STD-TEST) and tooling (STD-TOOL).
Frontmatter fields:
| Field | Meaning |
|---|---|
id | STD-<DOMAIN>-NNN, never reused |
type | Always rule |
status | draft, active or deprecated; only active rules are bundled |
applies_to | archetypes (build plan IDs; A15 does not exist) and languages |
core | true to inject for every task in a matching archetype |
severity | BLOCK or WARN need an active mechanical check; ADVISORY is review-only (CGD-08) |
enforcement | List of { kind, ref }; add planned: true for checks not built yet |
decisions | CGD IDs this rule implements |
last_verified | Date the rule was last checked against its enforcement and sources |
Enforcement kinds: eslint (rule name, optional options), tsconfig (compiler option, optional value), bp (A7 Delta banned pattern), semgrep (A7 Delta rule ID), policy (A7 checker control), preflight (preflight step), review (stage S1 to S3), script (must be planned until a runner exists).
Body sections, in order: ## Rule (80 words or fewer, no code), ## Do, ## Don't, optional ## Exceptions, ## Rationale, ## Related. Headings stop at H3. At least two wikilinks.
Validation
npm run validate:rules # Validate every rule
npm run validate:rules -- --bundle dist/rules.json # Validate, then write the pinned bundleThe validator checks every enforcement reference against the real ESLint, TypeScript and A7 Delta catalogs, so an invented rule name fails. It typechecks and lints each Do snippet and confirms each Don’t snippet is caught by one of the rule’s own checks. A fence written as ```ts nocheck skips compile and lint for snippets that import other modules. Don’t snippets whose only checks are policy, Semgrep or review cannot be replayed and are counted as unverified.