noxa

Crates.io CI MIT

Stop re-teaching your AI the same rules every session.

noxa hooks into Claude Code and automatically captures business rules from your conversations — then turns them into validation code, injects them into CLAUDE.md, and exposes them via an MCP server so Claude never forgets a constraint again.

You: "user.email cannot be null, I've said this a hundred times"
noxa: ✓ captured — validate_user_email_required() generated

The problem

Every time you start a new Claude Code session, your AI assistant has forgotten everything you taught it last time.

Session 1:  You: "invoice amounts cannot be negative"  →  Claude fixes it
Session 2:  Claude generates negative invoice amounts again
Session 3:  You repeat yourself. Again.

Domain rules, validation constraints, invariants — they live in your chat history and nowhere else. New team member? New session? Start from zero.

noxa makes your corrections permanent.


How it works

Claude Code session
      │
      ▼  Notification hook (passive, zero latency)
noxa intercept
      │
      ├─ 21 regex patterns  →  entity + constraint extracted
      ├─ Confidence scoring →  corrections get a boost
      └─ .noxa/rules.toml  ←─  atomic write, git-versioned
             │
      ┌──────┴──────────────────────┐
      ▼                             ▼
  CLAUDE.md                 validation.rs / .ts / .py
  (next session             (typed functions,
   starts informed)          ready to call)
             │
      noxa mcp  ←─ Claude queries rules in real time

Install

cargo install noxa

Requires Rust 1.70+ and Claude Code.


5-minute setup

Step 1 — Initialize

cd my-project && noxa init

Step 2 — Configure Claude Code

Add both the hook and the MCP server to .claude/settings.json:

{
  "hooks": {
    "Notification": [
      {
        "matcher": ".*",
        "hooks": [{ "type": "command", "command": "noxa intercept" }]
      }
    ]
  },
  "mcpServers": {
    "noxa": { "command": "noxa", "args": ["mcp"] }
  }
}

Run noxa hook-config and noxa mcp-config to print these snippets individually.

Step 3 — Work with Claude Code as usual. noxa listens silently.

Step 4 — After your session

noxa list                  # see what was captured
noxa review                # [c] confirm  [d] delete  [s] skip

noxa inject                # → update CLAUDE.md (next session starts informed)
noxa generate              # → .noxa/validation.rs
noxa generate --typescript # → .noxa/validation.ts
noxa generate --python     # → .noxa/validation.py

What gets captured

noxa recognizes constraint patterns in English and French — no configuration needed.

What you say to Claude What noxa captures
"user.email cannot be null" user.email → Required
"only one subscription per user" subscription → Unique per user
"trial period cannot exceed 14 days" trial.duration → Range [0, 14]
"plan_id cannot be changed after billing" subscription.plan_id → Immutable
"username cannot exceed 32 characters" user.username → Length max 32
"email must be a valid email" user.email → Format (regex)
"delete is forbidden" delete → Forbidden
"un seul rapport par portail" rapport → Unique per portail
"le solde ne doit jamais être négatif" solde → Forbidden
"il ne peut y avoir qu'un seul admin" admin → Unique

21 patterns total. Ambiguous phrases? Run noxa enrich — Claude Haiku improves the extraction automatically.


Generated code

Same rule, three languages. Pick what your stack uses.

Rust:

/// Auto-generated by noxa
pub fn validate_user_email_required(value: &str) -> Result<(), &'static str> {
    if value.trim().is_empty() { return Err("value is required and cannot be empty"); }
    Ok(())
}

TypeScript:

/** Auto-generated by noxa */
export function validateUserEmailRequired(value: unknown): void {
  if (value === null || value === undefined || String(value).trim() === '') {
    throw new Error('value is required and cannot be empty');
  }
}

Python:

def validate_user_email_required(value: str) -> None:
    """user.email must be required"""
    if not str(value).strip():
        raise ValueError("value is required and cannot be empty")

MCP server — Claude queries rules before coding

Add noxa mcp-config output to .claude/settings.json and Claude can call your rule store directly during a session:

Claude: [calls noxa_list_rules]
→ subscription.status must be unique per user
→ user.email must be required
→ trial.duration must be range [0, 14]

Claude: [generates code that already respects all three constraints]

No more corrections. No more re-teaching.

Available MCP tools: noxa_status · noxa_list_rules · noxa_explain_rule · noxa_confirm_rule · noxa_delete_rule


Audit — find unenforced rules

noxa audit
  STATUS      FUNCTION                            RULE
────────────────────────────────────────────────────────────────────────────────
  enforced    validate_user_email_required        user.email must be required
              ts: validateUserEmailRequired
              src/validators.ts

  missing     validate_subscription_status_…      subscription.status unique per user
              ts: validateSubscriptionStatusUniqueness

1/2 rules enforced — run `noxa generate` to create the missing function.

Scans .rs .ts .tsx .js .jsx .py — matches both Rust and TypeScript function names. Excludes target/ and node_modules/ automatically.


Share rules across projects

# Export confirmed rules
noxa export --confirmed > shared-rules.toml

# Import into another project (deduplication built-in)
cd other-project && noxa import ../shared-rules.toml
# ✓ imported 8/10 rules (2 already present)

All commands

Command What it does
noxa init Initialize .noxa/ in the current project
noxa status Dashboard: detected / confirmed / enforced
noxa list List all rules with ID, confidence, summary
noxa list --confirmed Confirmed rules only
noxa list --json JSON output for scripting
noxa review Interactive: confirm / delete / skip pending rules
noxa confirm <id> Confirm a rule by ID prefix
noxa delete <id> Delete a rule
noxa explain <id> Full rule details
noxa enrich Use Claude Haiku to improve low-confidence extractions
noxa inject Inject confirmed rules into CLAUDE.md
noxa generate Generate .noxa/validation.rs
noxa generate --typescript Generate .noxa/validation.ts
noxa generate --python Generate .noxa/validation.py
noxa audit Find which confirmed rules are used in the codebase
noxa export Export rules to a portable TOML file
noxa import <file> Import rules from an exported file
noxa mcp Start the MCP server (stdio transport)
noxa doctor Diagnose setup issues
noxa hook-config Print the Claude Code hook snippet
noxa mcp-config Print the MCP server configuration snippet

Global flag: --root <path> to target a project other than the current directory.


Rule store

Rules live in .noxa/rules.tomlcommit it. It's project state.

[[rules]]
id = "a3f2b1c0-4d2e-4f7a-b1c0-9d2e4f7a3b1c"
raw = "only one active subscription per user"
entity = "subscription"
property = "status"
confidence = 0.91
detected_at = "2026-07-08T14:23:00Z"
confirmed = true

[rules.constraint]
type = "unique"
per = "user"

Deduplication is built in — if noxa detects the same rule twice, it updates the confidence and moves on.


CLAUDE.md injection

After noxa inject, every new session starts with full context:

<!-- noxa:rules:start -->
## Business Rules (auto-captured by noxa)

- **subscription.status must be unique per user**: only one active subscription per user
- **user.email must be required**: user.email cannot be null
- **trial.duration must be range [0, 14]**: trial period cannot exceed 14 days
<!-- noxa:rules:end -->

Idempotent — safe to run multiple times.


Why noxa

  • Zero friction. Passive hook. You don't change how you work.
  • Git-native. Rules are a TOML file. Diff them, review them, version them.
  • Multi-language. Rust, TypeScript, Python — generate once, use anywhere.
  • MCP-ready. Claude queries constraints proactively instead of waiting for corrections.
  • AI-assisted recovery. noxa enrich uses Claude Haiku to improve fuzzy extractions.
  • Open source. MIT. No telemetry. No cloud. Your rules stay in your repo.

Roadmap

  • noxa export / import across teams with domain tagging
  • Spanish, German, Portuguese detection patterns
  • VS Code extension for inline rule visualization

Contributing

If noxa misses a rule pattern from your real usage, open an issue with the exact phrase. Detection coverage is built directly from real-world examples.


License

MIT — see LICENSE.

Part of rustkit-ai — open source Rust tools for the AI development era.