Event Organizer is moving to an agent-first operating model.
The product direction is:
/agentis the primary authenticated workspace- Modal is the execution authority for all agent logic and guardrails
- Convex stores product state, thread history, artifacts, and approvals
- Attio remains the CRM system of record for identity and speaker workflow
- Discord is a second client of the same agent runtime, not a separate automation path
The system is split into three layers:
| Layer | Responsibility |
|---|---|
fe+convex/ |
Next.js app surfaces, Convex queries/mutations, authenticated UI for /agent and dashboard drill-downs |
agent/ |
Modal-hosted agent runtime, MCP adapters, Attio/Convex integration helpers, Anthropic Agent SDK harness |
| Attio + Convex | Persistent business state: Attio for CRM truth, Convex for application state and agent interaction history |
The active MVP is the agent-first workspace:
- add a full-page
/agentsurface - route all agent execution through Modal endpoints
- use Anthropic Agent SDK inside Modal as the agent harness
- keep Next.js and Discord thin clients
- preserve existing dashboard pages as precise drill-down tools
- prune unrelated engineering from the MVP backlog
For the authoritative product and data-contract details, read:
PLAN.mdfor system contracts and ownershipAGENTS.mdfor operator/runtime rulesIMPLEMENTATION.mdfor the parallel execution planDESIGN.mdfor shared dashboard and monochrome UI guidanceWORK_ATTRIBUTION.mdfor contribution attribution based on closed GitHub pull requests
event_organizer/
├── fe+convex/ # Next.js 16 app + Convex functions
├── agent/ # Modal runtime, Attio helpers, MCP server, tests
├── PLAN.md # Architecture and data-contract source of truth
├── AGENTS.md # Operator and runtime integration guide
├── IMPLEMENTATION.md # Implementation workstreams and dependency plan
├── DESIGN.md # Frontend layout and design-system rules
└── WORK_ATTRIBUTION.md # Closed-PR contribution attribution record
Install these before starting local development:
| Tool | Install |
|---|---|
| Node.js 20+ | brew install node |
| Bun | curl -fsSL https://bun.sh/install | bash |
| Python 3.11+ | brew install python@3.11 |
| uv | curl -LsSf https://astral.sh/uv/install.sh | sh |
| Doppler CLI | brew install dopplerhq/cli/doppler |
| Modal CLI | python -m pip install modal |
Secrets are managed through Doppler. Do not create repo-local .env files.
One-time setup:
doppler login
cd /Users/sean_lai/event_organizer
doppler setupUseful validation:
doppler secretsMost work needs three terminals.
cd /Users/sean_lai/event_organizer/fe+convex
doppler run -- npx convex devcd /Users/sean_lai/event_organizer/fe+convex
doppler run -- bun devThe web app runs at http://localhost:3000.
Install Python dependencies:
cd /Users/sean_lai/event_organizer/agent
uv syncRun the packaged local MCP server if you are working on tool adapters:
cd /Users/sean_lai/event_organizer/agent
doppler run -- uv run python -m apps.mcp.serverInspect MCP tools interactively:
cd /Users/sean_lai/event_organizer/agent
doppler run -- npx @modelcontextprotocol/inspector uv run python -m apps.mcp.serverThe Modal runtime starts that same MCP server over stdio through the Claude agent SDK. The current tool surface is:
- Attio
people(identity only):search_people,get_person,upsert_person,append_person_note - Attio
speakers(workflow):search_speakers,get_speaker,ensure_speaker_for_person,update_speaker_workflow - Compatibility read aliases:
search_contacts,get_contact - Convex reads:
list_events,get_event,get_event_inbound_status,get_event_outreach,get_attendance_dashboard,get_event_attendance,get_event_room_booking - Approval-gated Convex writes:
create_event,update_event_safe - OnceHub live reads:
find_oncehub_slots(Leslie eLab Lean/Launchpad, always live) - Approval-gated OnceHub writes:
book_oncehub_room(booking under the shared club profile; upsertsevent_room_bookingsand stickiesevents.room_confirmed)
Deploy or serve Modal functions from the agent/ package as needed for runtime work.
These live in Doppler.
| Variable | Used by | Description |
|---|---|---|
ATTIO_API_KEY |
agent/ |
Attio API token |
BETTER_AUTH_URL |
fe+convex/ |
Auth base URL |
BETTER_AUTH_SECRET |
fe+convex/ |
Better Auth signing secret |
CONVEX_DEPLOYMENT |
fe+convex/ |
Convex deployment URL |
NEXT_PUBLIC_CONVEX_URL |
fe+convex/ |
Browser Convex URL |
NEXT_PUBLIC_MODAL_ENDPOINT |
fe+convex/ |
Base URL used by Next route handlers to proxy /api/agent/* requests to the Modal runtime |
CONVEX_URL |
agent/ |
Convex HTTP endpoint for Modal-side access |
CONVEX_DEPLOY_KEY |
agent/ |
Convex deploy key for server-side mutations |
ANTHROPIC_API_KEY |
agent/ |
Anthropic API key for the Modal runtime |
MODAL_TOKEN_ID |
agent/ |
Modal auth |
MODAL_TOKEN_SECRET |
agent/ |
Modal auth |
EVENT_ORGANIZER_CONFIG_PATH |
agent/ |
Optional path to a mounted YAML config file; defaults to agent/config.yaml |
ONCEHUB_PAGE_URL |
agent/ |
Optional emergency override for oncehub.page_url |
ONCEHUB_ROOM_LABEL |
agent/ |
Optional emergency override for oncehub.room_label |
OnceHub uses the internal browser API (no API key required). The runtime reads
page, room, and shared club booking-profile settings from agent/config.yaml, so
Modal does not need one environment variable per identity field. ONCEHUB_PAGE_URL
and ONCEHUB_ROOM_LABEL remain small emergency overrides for rotations, but the
normal production path is to edit or mount the YAML file. Before
book_oncehub_room sends a real booking request, the runtime validates that
required identity fields are no longer blank or FILL_IN placeholders.
| YAML path | Required? | What to fill |
|---|---|---|
oncehub.page_url |
Yes | OnceHub booking page URL, e.g. https://go.oncehub.com/NYULeslie. |
oncehub.room_label |
Yes | Pinned room label; current default is Lean/Launchpad. |
oncehub.booking_profile.first_name |
Yes | First name for the shared club booking identity. |
oncehub.booking_profile.last_name |
Yes | Last name for the shared club booking identity. |
oncehub.booking_profile.email |
Yes | NYU email address that should receive or own booking correspondence. |
oncehub.booking_profile.net_id |
Yes | NetID associated with the booking identity. |
oncehub.booking_profile.organization |
Yes | Club or organization name shown on the room request. |
oncehub.booking_profile.graduation_year |
Yes | Graduation year value expected by the OnceHub form. |
oncehub.booking_profile.location |
Yes | Event location value; current default is 16 Washington Place. |
oncehub.booking_profile.affiliation_id |
Yes | OnceHub dropdown id; current default 457707 means Undergrad. |
oncehub.booking_profile.school_id |
Yes | OnceHub dropdown id; current default 453247 means Tandon. |
oncehub.booking_profile.event_name |
No | Optional default event-name field; if blank or placeholder, runtime uses the requested event title. |
oncehub.booking_profile.pronouns_id |
No | Optional pronouns dropdown id; leave blank to skip. |
subject and num_attendees are supplied by the booking request at runtime, so
those defaults are retained only for local/template readability.
Frontend:
cd /Users/sean_lai/event_organizer/fe+convex
doppler run -- bun run lintAgent runtime:
cd /Users/sean_lai/event_organizer/agent
doppler run -- uv run pytest tests -vConvex schema/codegen refresh:
cd /Users/sean_lai/event_organizer/fe+convex
doppler run -- npx convex dev --once- Keep agent orchestration logic on the Modal side.
- Do not move tool policy or guardrails into Next.js or Discord handlers.
- Do not write speaker workflow state onto Attio
people. - Keep dashboard UI monochrome and consistent with
DESIGN.md. - If
PLAN.mdchanges in a way that affects runtime behavior, updateAGENTS.mdin the same change.
The active milestone is the agent-first MVP.
Anything not directly advancing one of these should be deferred:
/agentworkspace- Modal runtime
- Anthropic Agent SDK harness
- artifacts and approvals
- Discord parity on the shared backend
- required architecture-doc rewrites
doppler: command not found
- Install Doppler and restart your shell.
ATTIO_API_KEY must be set
- Run the process through
doppler run --.
Convex type drift after pulling
- Run
doppler run -- npx convex dev --onceinsidefe+convex/.
bun: command not found
- Restart your terminal or reload your shell profile.
Modal auth failures
- Confirm
MODAL_TOKEN_IDandMODAL_TOKEN_SECRETare present in Doppler and that you are logged in locally.