2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00
2025-11-11 23:11:59 -06:00

ADHDbot

ADHDbot is a FastAPI + Discord assistant that captures ADHD-friendly notes, breaks work into tiny steps, and pipes confirmed reminders into ntfy so your phone vibrates when it matters. The repo also bundles an hourly “agentic sweep” worker and a lightweight web console for experimenting with prompts and action items.

At a glance

  • Opinionated system prompt + tooling contract wired through OpenRouter (Claude Haiku 4.5 by default).
  • FastAPI surface area for chat runs, notes, and persistent action items—served by Docker or a bare Python venv.
  • Notification bridge that turns schedule_reminder JSON into ntfy pushes (bring your own topic + auth).
  • Hourly agentic workflow that summarizes memory + actions, then nudges the user via a dedicated prompt.
  • Static React console (web_App.tsx) for local demos: send prompts, review transcripts, and edit action items without curl.

Quick Start

  1. Copy the example environment file and fill in your secrets:
    cp .env.example .env
    # edit .env to insert your real OPENROUTER_API_KEY, DISCORD_BOT_TOKEN, TARGET_USER_ID, etc.
    
  2. Bring up the stack with docker-compose (recommended; includes host persistence for logs/notes):
    docker compose up -d --build
    
    • ./memory is bind-mounted into the container (./memory:/app/memory), so any saved notes appear in the repo directly.
    • .env is auto-loaded and the FastAPI service is exposed on http://localhost:8000.
    • The compose stack now launches two services: adhdbot (the FastAPI/Discord gateway) and agentic_worker, a companion process that runs the hourly sweep loop.
  3. Or build/run manually if you prefer the raw Docker commands:
    docker build -t adhdbot .
    docker run --rm -p 8000:8000 --env-file .env -v "$PWD/memory:/app/memory" adhdbot
    

Local development (no Docker)

  1. Create a virtual environment and install deps:
    python3 -m venv .venv
    source .venv/bin/activate
    pip install -r requirements.txt
    
  2. Copy .env.example to .env and fill in the same secrets the container expects.
  3. Launch the API with reload and rich logs:
    uvicorn api:app --reload --port 8000
    
  4. (Optional) start the hourly worker in another shell to mirror the compose setup:
    AGENTIC_INTERVAL_SECONDS=900 python agentic_worker.py
    
  5. Run one-off prompts without FastAPI by calling the helper scripts:
    # Runs the main conversational prompt (uses env defaults for category/name/context)
    python main.py
    
    # Forces the hourly sweep packet through the agentic prompt once
    python agentic_review.py
    

API usage

Once the container is running, hit the API to trigger a prompt flow:

curl -X POST http://localhost:8000/run \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "chelsea",
    "context": "Remind me in 10 minutes to stretch.",
    "history": [
      {"role": "user", "content": "Hi"},
      {"role": "assistant", "content": "Hello!"}
    ],
    "modeHint": "Reminder"
  }'

Endpoints:

  • GET /health simple liveness check.
  • POST /run conversational entry point. Fields:
    • userId (optional) defaults to TARGET_USER_ID.
    • context the latest user message.
    • history (optional) array of {role:"user"|"assistant", content:"..."} representing prior turns (most recent last).
    • modeHint (optional) short string that nudges tone/behavior ("Planning", "Reminder", etc.).
    • category / promptName remain for backward compatibility but no longer swap entire templates.
  • GET /users/{userId}/notes?limit=10 fetch the most recent notes (limit defaults to 10, use limit=0 for all).
  • POST /users/{userId}/notes persist a note manually by posting { "note": "text", "metadata": { ... } }.
  • GET /users/{userId}/memory full summaries + notes payload for the user.
  • GET /users/{userId}/actions list the modifiable daily/periodic action items tied to that user's memory.
  • POST /users/{userId}/actions create a new action item (title, optional details, cadence, interval_minutes).
  • PUT /users/{userId}/actions/{actionId} update an item in-place (title, cadence, interval, or details).
  • DELETE /users/{userId}/actions/{actionId} remove it entirely.
  • POST /users/{userId}/actions/{actionId}/progress append a progress entry (status, optional note) so the hourly sweep knows the latest state.
  • POST /users/{userId}/notes/test quick QA helper that reuses the welcome prompt with a custom context JSON body.
  • GET /prompts inspect the currently loaded prompt catalog.
  • POST /prompts/reload force a reload from the prompts/ folder.

Environment variables of interest (see .env.example):

  • OPENROUTER_API_KEY OpenRouter key used by AIInteraction.
  • DISCORD_BOT_TOKEN / TARGET_USER_ID / DISCORD_WEBHOOK_URL Discord plumbing.
  • PROMPT_CATEGORY, PROMPT_NAME, PROMPT_CONTEXT defaults for the /run endpoint.
  • LOG_PROMPTS (default 1) when truthy, every outgoing prompt is logged to stdout so you can audit the final instructions sent to the LLM.
  • NTFY_BASE_URL when set (e.g., https://ntfy.scorpi.us), reminder payloads with action: schedule_reminder will be POSTed to ntfy.
  • NTFY_TOPIC_TEMPLATE optional format string for topics (default adhdbot-{userId}); override per reminder via reminder.metadata.topic.
  • NTFY_AUTH_TOKEN optional bearer token if your ntfy server requires auth.
  • AGENTIC_CATEGORY / AGENTIC_PROMPT_NAME / AGENTIC_MODE_HINT control which prompt handles the hourly agentic sweep (defaults: agentic/hourly_review, hint "Agentic review").
  • AGENTIC_NOTES_LIMIT how many of the most recent notes to include in the sweep payload (default 5).
  • AGENTIC_OPERATOR_HINT optional text passed to agentic_review.py so you can bias the sweep for a given run (cron, manual nudge, etc.).
  • AGENTIC_INTERVAL_SECONDS cadence for the always-on worker loop (defaults to 3600 seconds/1 hour).

Frontend console

  • web_App.tsx + web_App.css describe a quick React shell that talks directly to /api/run and the action endpoints. Drop the file into any Vite/CRA sandbox or use it as design reference for your own console.
  • The UI stores chat history in localStorage, mirrors the three built-in prompts (“general”, “planning”, “reminders”), and exposes an action-item panel with CRUD + progress logging—so you can test the API without Postman.
  • When hosting the FastAPI server, make sure it serves static assets or proxy /api/* so the console can fetch without CORS gymnastics.

Reminder payloads

When the assistant schedules a reminder it emits a single JSON block:

{
  "action": "schedule_reminder",
  "reminder": {
    "message": "short friendly text",
    "topic": "adhdbot-<user id>",
    "trigger": {
      "value": "2025-11-11T02:41:42+00:00"
    }
  }
}

The backend automatically converts relative phrases ("in 10 minutes") into the ISO timestamp above and POSTs the message to the ntfy topic (default https://ntfy.scorpi.us/adhdbot-<user>), so subscribing to that topic on your phone is all you need for push notifications.

Daily / Periodic Action List + Hourly Agentic Sweep

  • Action items share the same storage as notes inside memory/<user>_memory.json under the action_items key. Each entry tracks title, cadence, optional interval_minutes, details, and a rolling progress history.
  • Use the action API endpoints (above) to add/remove/edit entries or append status updates—CLI, scripts, or the UI can call them exactly like the note endpoints. The bundled web_App.tsx (served by the static UI) now surfaces a lightweight management panel to create actions, log progress, and delete entries without touching curl.
  • AgenticWorkflow.buildReviewPacket compiles the latest notes plus the action list into a JSON blob and feeds it into the agentic/hourly_review prompt. The new helper script agentic_review.py calls this flow; point a cron/systemd timer at it (hourly) so the autopilot can look for overdue habits or opportunities.
  • agentic_worker.py wraps the same helper in a persistent loop. The agentic_worker service defined in docker-compose.yml runs it with the same .env file, so deploying the stack automatically keeps the hourly sweep online. Adjust cadence via AGENTIC_INTERVAL_SECONDS or stop the service if you prefer to trigger sweeps manually.
  • Customize the autopilot without code by editing prompts/defaultPrompts.json (or adding a sibling file) to adjust agentic/hourly_review, then reload prompts or rebuild the container.

Architecture cheat sheet

  • api.py (FastAPI): exposes chat, memory, action-item, and prompt-catalog routes. It uses Pydantic models for validation and wraps every handler with ensureUserId/MemoryManager helpers so non-FastAPI callers stay lean.
  • Runner.py + AIInteraction.py: glue between your request and OpenRouter. Runner is a thin façade; AIInteraction composes the system prompt, trims chat history, logs prompts when LOG_PROMPTS=1, and post-processes responses for memory + notifications.
  • Memory.py: owns all persistence under memory/<user>_memory.json (notes, summaries, and action_items). JSON blocks emitted by the model (take_note, schedule_reminder, etc.) land here before any downstream automations run.
  • Notification.py: watches the same responses for schedule_reminder payloads and relays them to ntfy with sanitized titles + timestamps. Leave NTFY_BASE_URL unset to disable the bridge without touching code.
  • AgenticWorkflow.py + agentic_worker.py: build the hourly sweep packet (latest notes, summaries, action progress) and push it through agentic/hourly_review. Run agentic_worker via Docker Compose or your own cron/systemd timer for 24/7 coverage.
  • DiscordGateway.py: optional DM/webhook plumbing so every assistant reply can bounce straight into Discord when DISCORD_BOT_TOKEN or DISCORD_WEBHOOK_URL is configured.
  • Prompts folder: prompts/defaultPrompts.json ships with sane defaults; drop additional JSON files in the same folder and call POST /prompts/reload to hot-swap templates. Tooling/JSON contract lives in prompts/tool_instructions.md.

Prompt + tooling customization

  • All templates live in prompts/defaultPrompts.json (and sibling files). Edit them and restart the service to take effect.
  • Shared tooling instructions live in prompts/tool_instructions.md. AIInteraction injects this file both into the system prompt and at the end of every user prompt, so any changes immediately affect how models emit take_note, store_task, or schedule_reminder JSON payloads.
  • PROMPTS.md documents each category plus examples of the structured JSON outputs that downstream services can parse.

Memory + notes

  • The memory subsystem watches LLM responses for fenced ```json payloads. When it sees {"action": "take_note", ...} it writes to memory/<user>_memory.json (now persisted on the host via the compose volume).
  • Each entry includes the note text, UTC timestamp, and the raw metadata payload, so other services can build summaries or downstream automations from the same file.

Debugging tips

  • Tail the container logs with docker compose logs -f adhdbot to see:
    • The final prompt (with tooling contract) sent to the model.
    • Memory ingestion messages like [memory] Recorded note for <user>: ....
  • If you swap models, change openRouterModel in AIInteraction.py (or surface it via env) and rebuild the container.
Description
An AI bot to help with adhd and med compliance. Reminds user of med times, chores in an AI powered fashion.
Readme 96 KiB
Languages
Python 56.3%
TypeScript 22.8%
HTML 10.8%
CSS 9.9%
Dockerfile 0.2%