montana/Русский/Логистика/CLAUDE.md

10 KiB

CLAUDE.md

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

Project Overview

SeaFare Montana is a maritime logistics AI agent platform. A single-page web app with a Flask API backend, Claude API agent with tool-calling, and PostgreSQL database (SQLite in dev). Deployed on Render.com free tier (Python 3.11) with auto-deploy from master.

Commands

# Run locally
python seafare_api.py                    # Starts Flask on port 5050

# Production (Render)
gunicorn seafare_api:app --bind 0.0.0.0:$PORT --workers 1 --threads 2 --timeout 120

# Check Python syntax before committing (all core files)
python -m py_compile seafare_api.py && python -m py_compile seafare_agent.py && python -m py_compile maritime_db.py && python -m py_compile moltbook_bot.py && python -m py_compile telegram_bot.py && python -m py_compile ais_provider.py && python -m py_compile equasis_parser.py && python -m py_compile marinetraffic_parser.py && python -m py_compile maritime_compliance.py

# Run tests
python -m pytest tests/ -v --tb=short

# Deploy: push to master triggers Render auto-deploy
git add <files> && git commit -m "message" && git push

Pre-commit hook runs automatically: syntax check → pytest → .env secret guard.

Architecture

index.html          ─── Single-page frontend (vanilla JS, Leaflet map, no framework)
    ↓ fetch /api/v1/*
seafare_api.py      ─── Flask REST API (auth, wallet, chat, admin endpoints)
    ↓ generate_response()
seafare_agent.py    ─── Claude API agent with 26 tools (tool-calling loop, max 7 iterations)
    ↓ _TOOL_DISPATCH dict → handler functions
maritime_db.py      ─── Database layer (19 tables, PostgreSQL/SQLite dual-mode)
    ↑ external data
config.py                ─── Centralized constants (version, rate limits, cache TTLs, fees, env var names)
marinetraffic_parser.py  ─── Ports DB (16,553 ports) + routing engine + cargo classification + premium tool helpers
ais_provider.py          ─── Unified AIS: AISStream WebSocket + AISHub REST + Digitraffic REST + MT fallback
equasis_parser.py        ─── IMO vessel registry (authenticated web scraping)
maritime_compliance.py   ─── Sanctions screening + dark fleet detection (standalone, no external deps)
moltbook_bot.py          ─── Promotional bot for Moltbook platform (background daemon)
telegram_bot.py          ─── Telegram bot: standalone service, group chats, vessel watch alerts

AI Agent (seafare_agent.py)

Uses Claude claude-sonnet-4-5-20250929 with tool-calling. The agent loop sends user message → Claude responds with tool_use blocks → _execute_tool_inner() runs them via _TOOL_DISPATCH dict → results sent back → repeats until stop_reason != "tool_use" (max 7 iterations via AGENT_MAX_TOOL_ITERATIONS). System prompt is action-oriented: agent detects request type and uses tools immediately, no filler text.

Tools (26): search_vessel, get_vessel_details, get_position, search_vessels_near_port, calculate_route, find_vessels_for_cargo, calculate_demurrage, search_contacts, unlock_contacts, get_freight_rate, screen_sanctions, check_port_congestion, get_bunker_prices, optimize_bunker, generate_charter_party, vessel_performance, generate_bill_of_lading, optimize_crew_change, calculate_insurance, estimate_port_costs, weather_routing, generate_fixture_recap, detect_ais_anomaly, detect_dark_fleet, search_web, get_revenue

user_context (profile summary + balance) is injected into the system prompt so the agent knows who it's talking to.

AIS Data Priority Chain (ais_provider.py)

For single vessel position (get_vessel_position):

  1. DB cache — fresh position (< 5 min)
  2. AISStream — persistent background thread OR sync fallback (8s WebSocket query in request thread)
  3. AISHub REST — on-demand query (1 min rate limit)
  4. Digitraffic — Finnish/Baltic waters (free, no key)
  5. MarineTraffic — scraping fallback
  6. Stale DB — old cache as last resort

Important: Daemon threads die on Render's gunicorn gthread workers. Sync fallback (query_position_sync, query_area_sync) runs inside Flask request threads and works reliably.

Vessel Search Features

Both search_vessels_near_port and find_vessels_for_cargo use expanding radius search:

  • Radius steps: 50 → 200 → 500 NM. First step uses full AIS provider (slow, ~6-8s). Wider steps use DB-only queries (instant).
  • Always returns at least 3 vessels (MIN_VESSELS). Each vessel has distance_nm and map_link.
  • map_link format: {{SHOWMAP~lat~lon~zoom~name}} — rendered as clickable buttons in chat by formatResponse() step 7 in index.html. Uses ~ delimiter (not |) to avoid markdown table conflicts.

Auth System (seafare_api.py)

Hybrid stateless + stateful: primary auth uses itsdangerous signed tokens (30-day TTL, survives Render DB wipes). Fallback to legacy UUID DB sessions. auto_promote_admin() checks ADMIN_EMAILS env var on every auth.

Payment Flow

search_contacts → free masked preview → user confirms → unlock_contactscharge_user() (atomic SQL WHERE balance >= ?) → add_service_charge()save_purchased_contacts(). Previously purchased contacts are returned free via has_purchased_contact().

i18n (Dual)

  • Server-side: TEXTS dict in seafare_api.py + L(lang, key) helper — for API error messages
  • Client-side: i18n JS object in index.html + t(key) helper — for all UI labels. Three languages: EN, RU, ES. Always add keys to all three.

Background Threads (seafare_api.py)

Two daemon threads auto-start at module level:

  1. Keep-alive (_start_keep_alive): pings /health every 14 min to prevent sleep
  2. Moltbook bot (_start_moltbook_bot): searches maritime posts on Moltbook every 30 min, generates expert comments via Claude Haiku

Telegram Bot (telegram_bot.py — separate systemd service)

Runs as standalone process (seafare-telegram.service), NOT inside gunicorn (daemon threads die on fork with --preload).

Features: Full AI agent (26 tools), group chat support (@mention/reply/commands), vessel watch alerts (/watch, /unwatch, /watches), auto language detection, per-user rate limiting in groups.

Vessel Watch: Background checker thread polls DB positions every 10 min. Arrival watches (one-shot) fire when vessel enters port radius. Status watches (continuous) fire on nav status changes. Max 5 watches per chat, auto-expire 7 days. DB table: vessel_watches.

Adding New Tools

  1. Add helper function in marinetraffic_parser.py (or maritime_compliance.py for compliance tools)
  2. Add tool definition to TOOLS list in seafare_agent.py (with input_schema)
  3. Add handler function _tool_<name>() in seafare_agent.py
  4. Add entry to _TOOL_DISPATCH dict in seafare_agent.py
  5. Add trigger rule in SYSTEM_PROMPT BEHAVIOR section
  6. Add UI service card in index.html + i18n keys in all 3 languages (EN/RU/ES)

Key Conventions

  • Versioning: APP_VERSION in config.py (semver). Bump with every commit: PATCH for fixes, MINOR for features, MAJOR for breaking changes. Displays in /health endpoint and sidebar footer.
  • Config centralization: All constants live in config.py (rate limits, cache TTLs, fees, env var names). Import from there, don't hardcode.
  • Data sources are secret: System prompt instructs agent to never reveal Equasis/MarineTraffic. Present data as "our maritime intelligence network."
  • Admin: is_admin users get free access to all paid features. Check via is_admin flag on user dict.
  • Atomic balance operations: Always use charge_user() (returns bool) — never manually subtract balance.
  • DB migrations: Use CREATE TABLE IF NOT EXISTS and CREATE INDEX IF NOT EXISTS in init_db(). No migration framework — backward-compatible additions only.
  • .env contains secrets — never commit. Credentials are set via Render dashboard env vars in production.
  • Single HTML file: All CSS, HTML, and JS live in index.html. No build step, no bundler.
  • Port database: world_ports.json — 16,553 ports from UN/LOCODE. Regenerate with python merge_unlocode.py.
  • Cargo classification: CARGO_TO_VESSEL dict in marinetraffic_parser.py maps cargo types → vessel categories (bulk, tanker, container, roro, general).

Database (PostgreSQL + SQLite)

Dual-mode: maritime_db.py auto-detects DATABASE_URL env var → PostgreSQL in production, SQLite locally. Wrapper classes (_PgCursorWrapper, _PgConnectionWrapper) translate SQLite-style ? placeholders to %s and auto-add RETURNING id to INSERTs. Always write SQL with ? placeholders — the wrapper handles conversion.

Tables (22): vessels, positions, contacts, port_calls, demurrage, users, sessions, chat_history, user_profiles, wallets, deposits, withdrawals, service_charges, purchased_contacts, port_vessel_cache, equasis_cache, equasis_daily_counter, query_log, moltbook_comments, user_memory, conversation_summaries, vessel_watches

All user-related tables FK to users(id). Vessel-related tables use mmsi as key.

Environment Variables

Variable Purpose
ANTHROPIC_API_KEY Claude API (required for AI agent + Moltbook bot)
EQUASIS_USER / EQUASIS_PASS Equasis.org login
GOOGLE_CLIENT_ID Google OAuth
ADMIN_EMAILS Comma-separated admin emails (auto-promoted on login)
SECRET_KEY Token signing (falls back to ANTHROPIC_API_KEY)
MOLTBOOK_API_KEY Moltbook platform API key (bot disabled if not set)
AISSTREAM_API_KEY AISStream.io WebSocket API key (real-time AIS)
AISHUB_USERNAME AISHub.net contributor username (REST AIS queries)
DIGITRAFFIC_ENABLED '1' (default) to enable Finnish Digitraffic AIS, '0' to disable
TELEGRAM_BOT_TOKEN Telegram Bot API token from @BotFather (bot disabled if not set)
DATABASE_URL PostgreSQL connection string (auto-set by Render; if absent → SQLite)