Skip to content

Latest commit

 

History

History
156 lines (109 loc) · 7.34 KB

File metadata and controls

156 lines (109 loc) · 7.34 KB

watcher — Agent Guidelines

Be terse. Prefer fragments over full sentences. Skip filler and preamble. Sacrifice grammar for density. Lead with the answer or action.

Project Overview

Web service for monitoring cannabis industry activity: licenses, regulatory filings, compliance events, and entity relationships.

Development Methodology

TDD required. Red → Green → Refactor. No production code without a failing test first.

Environment & Tooling

Python ≥3.12, uv, pytest, ruff; Node.js + npm (for Tailwind CLI — sudo npm install -g @tailwindcss/cli, one-time VM setup).

Project Layout

Top-level directories. Read the code for per-file detail.

src/api/         FastAPI app (ASGI routes, schemas, deps)
src/core/        Shared domain logic (models, probe, watches, notifications, diff, extractors, fetchers, scheduler, storage, crypto)
src/dashboard/   Server-rendered UI (Jinja2 + HTMX + Tailwind)
src/workers/     Procrastinate task queue (check_watch, schedule_tick, pipeline)
tests/           Mirrors src/ structure
deploy/          Systemd units and deployment config
docs/            Reference docs (COMMANDS, DEPLOYMENT, SKILLS, STYLE)
scripts/         Build scripts (Tailwind, vendor CSS, cleanup)
skills/          Agent skills (committed overrides + symlinks → skills-vendor/)
skills-vendor/   Git submodules for external skill repos
.claude/skills/  Claude Code skill discovery (symlinks → ../../skills/<name>)

Infrastructure

Single-VM setup. Dev and prod on the same VM. Code committed to main is the deployed code. Systemd service watcher runs the live site on port 8000.

Service Port Managed by
API (live) 8000 systemctl (watcher.service)
API (dev) 8001 manual uvicorn

The exe.dev proxy forwards 3000–9999. Dev server reachable at https://watcher.exe.xyz:8001/.

Server Lifecycle

Port 8000 belongs to systemd. Never start uvicorn manually on port 8000.

After committing to main: sudo systemctl restart watcher. After DB model changes: uv run alembic upgrade head then restart. After Tailwind/vendor CSS changes: bash scripts/build-css.sh then restart. Logs: sudo journalctl -u watcher -f.

Dev server (port 8001, leaves prod alone):

export $(cat /etc/watcher/.env .env 2>/dev/null | xargs)
uv run uvicorn src.api.main:app --host 0.0.0.0 --port 8001 --reload

Full lifecycle reference + cleanup timer: docs/DEPLOYMENT.md.

Environment Files

Two env files load in order (later overrides earlier):

  1. /etc/watcher/.env — production secrets (DATABASE_URL, APPRISE_SECRET_KEY). Persistent, managed manually on the VM.
  2. .env (repo root, git-ignored) — dev/agent secrets (GH_TOKEN, TEST_DATABASE_URL). Never commit.

Load both for shell commands:

export $(cat /etc/watcher/.env .env 2>/dev/null | xargs)

Full variable reference: docs/DEPLOYMENT.md.

Common Commands

uv sync                                      # install deps
uv run pytest                                # tests
uv run pytest -m integration                 # integration tests (needs PostgreSQL)
uv run ruff check .                          # lint
uv run alembic upgrade head                  # apply migrations
uv run alembic revision --autogenerate -m "description"

Full reference: docs/COMMANDS.md.

Agent Skills

Skills live in skills/ (agentskills.io) and .claude/skills/ (Claude Code). Local overrides in skills/ shadow vendor submodules in skills-vendor/.

Skill Triggers / when to invoke
reviewing-code-claude CR, code review
reviewing-architecture-claude AR, architecture review
shipping-work-claude ship it, push GH, close GH, wrap up
brainstorming brainstorm, design this, let's design
writing-plans write plan, implementation plan
writing-skills write skill, new skill, author skill
systematic-debugging any bug, test failure, unexpected behavior
verification-before-completion before any completion claim or commit
test-driven-development before writing implementation code
subagent-driven-development dispatch agents for plan execution
dispatching-parallel-agents 2+ independent tasks in parallel
using-git-worktrees feature work needing isolation
managing-skills-claude add skill repo, manage external skills
socraticode (codebase MCP) search before reading; codebase_search, codebase_graph_query, codebase_impact before opening files

Full skill reference + SocratiCode tool-selection table: docs/SKILLS.md. Cross-project search to the sister notifier index requires a per-instance .claude/settings.local.json (gitignored) — see "Linked Projects" in docs/SKILLS.md.

Conventions

Commit Messages:

#<number> [type]: <description>      # with issue
[type]: <description>                # without issue

Types: feat, fix, refactor, docs, test, chore.

Logging:

from src.core.logging import get_logger
logger = get_logger(__name__)

Entry points only: call configure_logging() once.

Date & Time: All UTC. ISO 8601: YYYY-MM-DDTHH:MM:SS.ffffffZ (timestamps), YYYY-MM-DD (dates).

General:

  • No inline module imports; all at file top
  • Docstrings for public modules, classes, functions
  • Test structure mirrors source (src/foo.pytests/test_foo.py)
  • Explicit imports only
  • Small, focused functions

DB Triggers (gotcha):

  • Triggers live in Alembic migrations (CREATE OR REPLACE FUNCTION + CREATE OR REPLACE TRIGGER; downgrade with DROP TRIGGER IF EXISTS … ON table; DROP FUNCTION IF EXISTS …).
  • Integration tests use Base.metadata.create_all (not migrations), so triggers are NOT applied automatically. Any trigger added in a migration must also be recreated in tests/conftest.py inside the test_engine fixture, after create_all.
  • Current triggers: trg_changes_update_last_changed_at (AFTER INSERT ON changes → sets watches.last_changed_at = NEW.detected_at).

Style & UI

Authoritative reference: docs/STYLE.md.

Brand: Cannabis Observer — co-purple-600 (#6d4488) primary accent. Never use brand colors for semantic status (green/yellow/red/blue).

Dark Mode: Tailwind dark: variants on every color utility. Class-based toggle (<html class="dark">). localStorage key: watcher-color-scheme.

Accessibility: WCAG 2.1 AA. Skip link, ARIA landmarks, focus-visible rings, 44px touch targets, aria-live on HTMX swap targets, reduced motion. Wrap decorative emoji in <span aria-hidden="true">. No title attributes.

CSS: Tailwind v4 with @theme in input.css. Use component classes (.btn, .badge, .stat-card, .data-table, .form-input, .link, .segment-group, .segment, .chip-group, .chip, .detail-grid, .toggle, .danger-zone). Badge variants: .badge-active (green), .badge-inactive (gray), .badge-archived (amber), .badge-error (red), .badge-warning (orange), .badge-info (blue). Use CSS logical properties (margin-inline-start not margin-left).

HTMX: OOB flash via partials/flash_oob.html. CSS .htmx-request for loading states. Detect HTMX via HX-Request header with HX-Boosted guard. All mutation routes provide non-HTMX redirect fallback.

Performance: Pre-built Tailwind (no CDN). BUILD_ID env var for cache-busting (?v={{ build_id }}). defer on all non-critical scripts. System font stack.