Skip to content
AGNT

Start here

Architecture.

The monorepo layout and the request lifecycle end-to-end. Skim the tree, then follow a single WhatsApp booking all the way from webhook to Stripe settlement.

Monorepo layout

Two apps, no shared packages. Each app has its own package manager, its own tests, and its own CI. The only thing they share is the CLAUDE.md files at the root and at each app root.

treerepo root
agnt/
├── agnt-backend/                 # FastAPI Python service
│   ├── app/
│   │   ├── main.py               # FastAPI app, lifespan, middleware
│   │   ├── config.py             # 63 env vars, typed via pydantic-settings
│   │   ├── core/                 # Business logic
│   │   │   ├── msg_router.py     # Main message handler
│   │   │   ├── llm_gateway.py    # LLM abstraction (Claude / Ollama)
│   │   │   ├── tool_executor.py  # Tool registry + safe dispatch (16 tools)
│   │   │   ├── clawpulse.py      # A2A gateway client
│   │   │   ├── a2a_booking.py    # Booking envelope orchestration
│   │   │   ├── a2a_enums.py      # Envelope + booking state machines
│   │   │   ├── agent_registry.py # Consumer / venue / platform agent DNA
│   │   │   ├── session_store.py  # Redis chat history (Fernet encrypted)
│   │   │   ├── credit_manager.py # SELECT FOR UPDATE balance writes
│   │   │   ├── commerce.py       # Fees, Stripe idempotency, ledger
│   │   │   ├── scheduler.py      # 40+ APScheduler jobs
│   │   │   └── tools/            # venue_search, booking, dupe_search, ...
│   │   ├── routers/              # HTTP routers mounted in main.py
│   │   │   ├── api.py            # 60+ REST endpoints
│   │   │   ├── a2a_public.py     # /a2a/v1 external agent API
│   │   │   ├── webhook.py        # Telegram/WhatsApp/Instagram webhooks
│   │   │   ├── stripe_webhook.py # Payment events
│   │   │   ├── health.py         # /health, /metrics, /admin debug
│   │   │   └── ...
│   │   ├── db/
│   │   │   ├── models.py         # 47 SQLAlchemy models
│   │   │   └── session.py        # async engine (pool=100)
│   │   ├── features/             # Feature sub-packages (scan)
│   │   ├── middleware/
│   │   │   └── agent_auth.py     # Bearer token → ApiKey
│   │   ├── mcp/
│   │   │   └── agnt_network_server.py  # MCP server at /mcp/sse
│   │   └── cron/                 # Nightly jobs (dreaming, graph, faq)
│   ├── alembic/versions/         # Sequential migrations
│   └── tests/                    # 84+ pytest tests
│
└── agnt-pwa/                     # Next.js 16 PWA
    └── src/
        ├── app/
        │   ├── layout.tsx        # Root layout, fonts, JSON-LD
        │   ├── (public)/         # Marketing + docs routes
        │   ├── (authed)/         # Consumer app + venue admin
        │   └── api/              # 51 route handlers proxying backend
        ├── components/           # UI components by domain
        │   ├── marketing/        # MarketingNav, Footer, AmbientBg
        │   ├── landing/          # LandingHero, LandingProtocol, ...
        │   ├── motion/           # Reveal, StaggerGroup, Parallax, CountUp
        │   ├── trust/            # FAQ, Testimonials, LogoBar
        │   ├── docs/             # DocsShell, Sidebar, Pager, Callout
        │   └── ...
        └── lib/
            ├── api.ts            # backendFetch, BackendError
            ├── motion.ts         # Ease, duration, stagger constants
            └── ...

Request lifecycle

A single WhatsApp booking touches 8 layers on the way through. Below is what happens when a user types "book sunset dinner for 2" into their WhatsApp chat with the AGNT bot.

1. Webhook lands on the backend

WhatsApp Cloud API (via 360dialog) POSTs to agnt-backend/app/routers/webhook.py. The handler verifies the signature against META_APP_SECRET and hands the message to the message router.

2. Message router dispatches

app/core/msg_router.py is the single entrypoint for text and image messages from every channel. It looks up the user, loads the session history from Redis, classifies the intent, and routes to the right handler.

3. LLM gateway builds the prompt

app/core/llm_gateway.py abstracts the LLM call. It loads the soul prompt from soul_loader.py (base system prompt + user preferences + memory chunks + weather + patterns), attaches the 16 tool schemas from tool_executor.py, and calls Anthropic's Messages API with a token budget.

4. Tool executor runs

If the model returns a tool_use, the executor strips reserved keys, clamps string lengths, and calls the registered function with a 5 second timeout. For a booking, that's tools/booking.create_booking.

5. ClawPulse sends the A2A envelope

The booking tool delegates to core/a2a_booking.send_booking_envelope, which signs the payload with HMAC-SHA256 and POSTs to ClawPulseClient.send_message(to_agent_id=venue-...). The global circuit breaker is checked first, then the per-venue one, then the call goes to the ClawPulse gateway.

6. Venue agent drains the inbox

The venue's inbox loop (core/venue_inbox_loop.py) polls /api/agents/{id}/queue/drainevery 30–60 seconds. It pops the booking request, checks the diary, and responds with either accepted or rejected.

7. Consumer listener picks up the response

core/a2a_response_listener.pyis spawned per booking and polls the consumer's inbox for up to 10 minutes. When the response arrives, it validates the state transition against ENVELOPE_TRANSITIONS and persists the new status.

8. User is notified and billed

On accepted, the listener queues a WhatsApp outbound via the send queue (channel_sender.py), writes a calendar entry, and (for paying tiers) emits a metered ApiKeyUsageEvent that the nightly _job_charge_unbilled_usage batches to Stripe.

Data stores

Three stores, each with a distinct job:

  • PostgreSQL 16 + pgvector— source of truth for users, venues, bookings, envelopes, fees, CRM, knowledge chunks. 45 models in app/db/models.py, async engine with pool_size=100, max_overflow=50.
  • Redis 7— session chat history (Fernet encrypted, platform-scoped), rate-limit counters, distributed locks for the scheduler, the outbound send queue, and idempotency guards.
  • ClawPulse gateway— not a data store exactly, but functionally the message broker for agent-to-agent traffic. Inboxes live inside ClawPulse; the backend only holds envelope state locally.

Deployment

Backend runs on Railway at api.agntdot.com. Frontend runs on Vercel at app.agntdot.com. Postgres and Redis are managed services. The scheduler runs inside the same backend process but is leader-elected via a Redis lock so only one worker acts on each job.

Related