Files
copilot/CLAUDE.md
T
2026-09-06 04:41:40 +02:00

5.7 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Repository state

This repo currently contains only a spec (NEXA_SPEC.md), README.md, and LICENSE — no source code, package.json, or manifest.json exist yet. There are no build/lint/test commands to run because nothing has been scaffolded. When implementation begins, this file should be updated with the actual commands (build, lint, test, load-unpacked instructions) once a package manager and bundler are chosen.

What this project is

Nexa is a blockchain-powered trading companion focused on the emotional/behavioral side of trading, not the trades themselves. Trades are already visible on-chain, so Nexa observes wallet activity rather than requiring manual logging. This repo is the open-source frontend: a browser extension. The backend (wallet/RPC listening via Solana/Helius, loss detection, auth, WebSocket push) is a separate private service and is out of scope here — treat it as an external API.

License: Apache 2.0. The backend stays closed-source; this frontend repo is the OSS component.

Full behavioral spec lives in NEXA_SPEC.md — read it before implementing the lockout feature or any site adapter/intervention. Key points below are a summary, not a replacement.

Target platform

  • Built and tested primarily on Zen (Firefox fork), must also work cross-platform on Firefox and Chromium-based browsers (WebExtensions API / Manifest V3 where possible).
  • Avoid browser-specific APIs unless behind a compatibility shim.

Current milestone: "Lockout" feature

When the extension receives a "locked" state, it visually disables (not hides) buy-action elements on supported trading sites, shows a non-dismissible-to-unlock reason toast, and intercepts clicks that reach the underlying element. Sell/manage actions are never touched. Unlocking reverses all DOM changes cleanly with no leftover overlays/classes.

Escalation model: first disable new-position buy actions only; if circumvented, escalate to a full-site block (stub only for v1).

Required architecture (modularity is the core constraint)

This is the most important design rule in the spec: lock/unlock decision-making, site-specific detection, and enforcement/intervention must be three fully decoupled concerns.

  • Adding a new supported site = a new site adapter module, without touching core logic.
  • Adding a new intervention type (full-site block, delayed buy with countdown, confirmation modal) = a new intervention strategy module, without touching adapters.
  • The decision of when/how long/why to lock is decoupled from how it's enforced on the page and from how it's detected on the page.

Planned structure (from NEXA_SPEC.md §3.2):

/src
  /background            - owns WebSocket connection to backend, holds current lock state, messages content scripts
  /content-scripts
    /adapters
      axiom.ts            - site-specific selectors + DOM strategy for axiom.trade
      adapter-interface.ts - shared type/interface all adapters implement
    /interventions
      blur-disable.ts       - visual lock treatment (v1 default)
      full-block.ts         - escalation: full page block overlay (stub for v1)
      intervention-interface.ts
    observer.ts           - generic MutationObserver watching for adapter-declared selectors (SPA-safe)
    content-index.ts      - wires adapter + intervention + background messages together
  /popup                 - status, reason for lock, threshold settings link
  /notifications         - toast/banner injected into page or via browser notification API
  /shared
    messaging.ts          - typed message contracts between background <-> content scripts <-> popup
    types.ts
manifest.json

A site adapter's contract: matches (URL pattern), findBuyElements(), getContainer(el) (stable ancestor to style, so the whole control is styled rather than an inner span).

Axiom.trade adapter specifics (first target site)

  • Axiom is a React SPA — buy elements mount/unmount without full page reloads. Use a MutationObserver on a stable root (e.g. document.body), not a one-time querySelectorAll on load.
  • Quick Buy button: find via closest('.buy-click-container'), not a hardcoded ancestor depth (DOM depth is not stable).
  • Noob Mode Buy button: match button elements with class bg-increase whose text matches /^Buy\s/i. Do not hardcode token names — they vary per token page.
  • Full selector details and example markup are in NEXA_SPEC.md §3.3.

Lock state contract

The lock/unlock state is a simple typed interface: { locked: boolean, reason?: string, scope: 'buy-only' | 'full-block' }. For v1 (no real backend yet), this is driven by a mock/dev toggle (e.g. via popup or browser.storage). The background script must expose a single isolated seam (getLockState() / setLockState()) where the real WebSocket client will later plug in — do not scatter lock-state reads/writes across modules.

Visual treatment for v1 (blur-disable)

  • Wrap or overlay the original element rather than mutating its classes destructively, so the original markup can be restored exactly on unlock.
  • filter: blur(2-3px), ~0.5 opacity, cursor: not-allowed, a non-blurred centered lock icon overlay, and pointer-events: none (or a transparent click-catcher div).
  • A click on a locked element (or its click-catcher) must trigger the same reason toast as lock activation.

Non-goals for this milestone

  • No real backend/WebSocket connection (mock state only).
  • No cost-basis tracking logic (backend concern).
  • No full-site-block implementation beyond a stub module.
  • No threshold-setting UI (placeholder link only).
  • Only the axiom.trade adapter needs to be functional; the architecture just needs to make adding more sites trivial.