| description | Use Deno instead of Node.js, npm, pnpm, or vite. |
|---|---|
| globs | *.ts, *.tsx, *.html, *.css, *.js, *.jsx, deno.json |
| alwaysApply | false |
deno run --allow-all <file>, notnode/ts-nodedeno test, notjest/vitestdeno install, notnpm/yarn/pnpm installdeno task <name>for tasks defined indeno.json;npx <pkg>only for CLI not on JSR.envis loaded via--envin task definitions — don't usedotenv
JSR packages (supply-chain safe, no npm):
hono→jsr:@hono/honozod→jsr:@zod/zod@noble/hashes→jsr:@noble/hashes- Test imports:
@std/testing/bdd+@std/expect
npm packages (via npm: prefix):
@cashu/cashu-ts,nostr-tools,@anthropic-ai/sdk,@modelcontextprotocol/sdk- React/UI:
react,react-dom,@tanstack/react-query,lucide-react,radix-ui,clsx,tailwind-merge,class-variance-authority
Deno.serve()for HTTP servers. Use Hono for routing. Don't useexpress.Deno.upgradeWebSocket()for WebSocket support.- Runtime compat layer at
packages/core-runtime/exposes:spawn,readFile,writeFile,fileExists,fileLastModified,which,moduleDir. Import as@anchr/core-runtime(or subpaths like@anchr/core-runtime/logger). - Env access: use
Deno.env.get/set/delete— neverprocess.env(caught by lint). WebSocketis built-in. Don't usews.
Use logTape via @anchr/core-runtime/logger (re-exposed for the host as src/infrastructure/logger.ts). Don't call console.* in src/infrastructure/ or packages/ — console is reserved for UI/scripts and the log-stream tee.
import { getLogger } from "@anchr/core-runtime/logger";
const log = getLogger(["anchr", "verifier"]);
log.info("verification passed", { queryId, oracleId });The level is read from ANCHR_LOG_LEVEL (or LOG_LEVEL) — info by default.
Tests use @std/testing/bdd (describe/it/test) + @std/expect. Run with deno test.
UI is pre-built with esbuild (deno task build:ui) and served as static files via Hono's serveStatic:
import { serveStatic } from "hono/deno";
app.get("/", serveStatic({ path: "./dist/ui/index.html" }));
app.get("/assets/*", serveStatic({ root: "./dist/ui/" }));
Deno.serve({ port }, app.fetch);Run the server:
deno task build:ui && deno task build:css && deno task dev| Command | Scope | Docker |
|---|---|---|
deno task lint |
recommended deno-lint rules + no-eval / no-self-compare / default-param-last | No |
deno task lint:strict |
deno lint + arch + invariants + paths + refactor | No |
deno task test:packages |
per-package tests across all 7 workspace members | No |
deno task test:all |
deno lint + arch + invariants + paths + dep audit + unit + protocol + frost + integration + example + pentest | No |
deno task test:all:docker |
e2e relay + regtest (starts/stops Docker) | Yes |
deno task test:all:full |
all of the above combined | Yes |
./scripts/test-all.sh --ci |
same as full, CI-optimized | Yes |
Additional CI invariants beyond what the APIs / Logging sections already require: no --no-check in test tasks; no dynamic await import(...) in libraries (platform conditionals + scripts only).
ascasts andanyare forbidden insrc/andpackages/. Narrow with type predicates (x is T) or runtime helpers insrc/infrastructure/lib/runtime-types.ts.unknownis allowed only at genuine boundaries (HTTP body parsing,JSON.parse,catch (err)) — narrow before use.- Enforced by
deno task lint:refactor.
Pre-1.0 (current): when a function, field, or endpoint is replaced, delete the old path outright. No @deprecated aliases, "legacy" fallbacks, or "backward compat" shims. If regression is the worry, lock the new behavior with a test.
Post-1.0 (future): @deprecated only on minor/patch boundaries, naming the introduce + remove versions (@deprecated since v1.4, removed in v2.0. Use X.). Major versions delete.
Enforced by deno task lint:deprecation, which bans @deprecated, "deprecated", "legacy", "backward(s) compat" in *.ts/*.tsx/*.rs. Per-line opt-out: allow-deprecation-vocab: <reason> (reserved for legitimate post-1.0 notices). Markdown is not scanned.
Default to no comments. Delete any comment that restates the code, narrates the change ("added for X", "previously did Y", "belt and suspenders so…"), or paraphrases an explicit expression. Keep one only for a non-obvious WHY (hidden invariant, workaround for a referenced bug, surprising ordering). When editing, strip violating comments in the touched region — don't preserve them out of politeness.
- A change is "done" only after a full local run passes:
deno task test:all(lint + unit + protocol + frost + integration + example + pentest) plusdeno task test:all:docker(Docker-backed e2e: relay + regtest). Don't claim done after only unit tests. - If a test or check fails, fix the implementation. Do not skip the test, weaken the assertion, delete the case, or
--no-checkaround it. Iterate on root cause until tests pass with the correct behavior.
deno task lint:arch enforces Clean Architecture layer dependencies:
| Rule | Layer | Must NOT import from |
|---|---|---|
| E001 | domain/ |
application, infrastructure, ui, runtime |
| E002 | runtime/ |
domain, application, infrastructure, ui |
| E003 | ui/ |
infrastructure, application |
| E004 | Any | express, dotenv, ws (banned packages) |
| E005 | application/ |
infrastructure, ui, runtime |
| W001 | Any | npm: when JSR equivalent exists |
- Runs automatically on every Edit/Write via Claude Code hook (PostToolUse)
- Runs in CI before typecheck
- Errors (E*) cause non-zero exit; warnings (W*) are informational
DESIGN.md is the source of truth for fonts, colors, spacing, and visual direction. Don't deviate without explicit approval; in QA mode, flag drift.
When a request matches an available skill, invoke it via the Skill tool as the first action — don't answer directly or run other tools first. Available skills are listed in the system reminder; trust their own descriptions for routing.