Skip to content
BugsBunnyWandersPublic

About

Personal Agentic AI assistant

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Eva AI

Eva is a proactive, event-driven personal AI operator. The repository contains the application foundation, durable Event backbone, Gmail ingestion, Goal and Situation domain, relevance engine, scoped long-term memory, bounded email investigation, user-specific Telegram conversation, and approval-gated Gmail drafting and sending.

Requirements

  • Python 3.14 (managed automatically by uv)
  • uv 0.12+
  • Docker with Docker Compose

Local setup

Copy .env.example to .env, then run:

make setup
make db-up
make migrate
make run

The API listens on http://127.0.0.1:8000.

curl http://127.0.0.1:8000/health/live
curl http://127.0.0.1:8000/health/ready

Both endpoints return HTTP 200 when the application and database are ready.

GCP deployment

Milestone 5.5 packages the API and continuous worker into one immutable image and provisions the production runtime with Terraform. Pull requests receive no Google credential; after CI succeeds on main, GitHub Actions authenticates through Workload Identity Federation, applies Terraform with workers paused, runs migrations, restores the configured worker count, and checks API readiness. The same stack provisions a bounded Cloud Tasks queue and a private, IAM-authenticated action executor. Proposal and dispatch paths use EVA_ACTIONS_ENABLED; the private runtime uses the separate EVA_ACTION_EXECUTOR_ENABLED boot gate. The one-time bootstrap and first Gmail activation steps are in the GCP deployment guide.

Public website

Eva's dependency-free public website lives in site/. It provides the product homepage and the stable policy URLs used by Google OAuth:

  • https://evaatyourservice.com/
  • https://evaatyourservice.com/privacy/
  • https://evaatyourservice.com/terms/

Preview the site locally without starting Eva's backend:

uv run python -m http.server 8080 --directory site

Open http://127.0.0.1:8080. The site contains no external scripts, analytics, cookies, or build-time dependencies. Its structural and policy contract tests run as part of make verify.

GitHub Pages deployment

The Deploy public site GitHub Actions workflow publishes site/ after a site-related change reaches main. In the repository's Settings → Pages, select GitHub Actions as the build source if it is not selected automatically. Configure the custom domain as evaatyourservice.com before changing DNS; GitHub recommends setting the custom domain first to reduce takeover risk.

After the custom domain is saved in GitHub, add these records in Hostinger's DNS Zone Editor:

Type Name Target
A @ 185.199.108.153
A @ 185.199.109.153
A @ 185.199.110.153
A @ 185.199.111.153
CNAME www bugsbunnywanders.github.io

Do not remove or replace existing MX or TXT records used for email, ownership, or other services. Wait for GitHub's DNS check to pass, then enable Enforce HTTPS. DNS and certificate issuance can take time to propagate.

Google OAuth production handoff

Once all three HTTPS URLs resolve publicly:

  1. Verify evaatyourservice.com in Google Search Console, normally with the DNS TXT method.
  2. In Google Auth Platform → Branding, set the application homepage to https://evaatyourservice.com/, the privacy policy to https://evaatyourservice.com/privacy/, and the terms link to https://evaatyourservice.com/terms/.
  3. Add evaatyourservice.com as an authorized domain and save the branding configuration.
  4. In Audience, publish the OAuth app to In production. Personal use can remain unverified, but Google may show an unverified-app warning.
  5. Reauthorize the Gmail connector after production publishing so the local Testing refresh token is replaced with a production authorization.

The Pages merge does not itself change Hostinger DNS, verify Search Console, publish the OAuth app, or rotate Gmail authorization. Those remain deliberate operator steps.

Gmail ingestion

Milestone 2 adds Desktop OAuth bootstrap, Gmail watch/history synchronization, a Google Pub/Sub pull subscriber, persisted watch maintenance, and expired-cursor recovery. Setup requires manual Google Auth Platform configuration and local GCP resources; follow the Gmail ingestion operator guide before running the worker.

The local command surface is:

uv run eva scope create --display-name "Saswat Ray" --workspace-name personal
uv run eva gmail connect --user-id USER_UUID --workspace-id WORKSPACE_UUID
uv run eva gmail sync --connector-id CONNECTOR_UUID
uv run eva gmail pull
uv run eva gmail maintain

The four Gmail Make wrappers consume IDs from exported environment variables as literal shell data. Create the scope with the direct CLI command above, export the UUIDs it prints, then use:

export EVA_USER_ID=USER_UUID
export EVA_WORKSPACE_ID=WORKSPACE_UUID
export EVA_GMAIL_CONNECTOR_ID=CONNECTOR_UUID
make gmail-connect
make gmail-sync
make gmail-pull
make gmail-maintain

There is no public Gmail webhook or HTTP ingestion endpoint. Gmail notifications are consumed from the configured pull subscription.

Verification

With PostgreSQL running:

make verify

This runs Ruff formatting and lint checks, strict mypy checking, unit tests, PostgreSQL integration tests, and migration verification.

Database migrations

Create revisions deliberately and review them before applying:

uv run alembic revision --autogenerate -m "describe change"
uv run alembic upgrade head

Migrations never run automatically during API startup.

Architecture

The product architecture is in spec/2026-08-29-proactive-personal-ai-agent-design.md. Milestone designs and implementation plans are stored under docs/superpowers/.

Milestone 1: Event backbone

Milestone 1 adds a durable event backbone with this flow:

NewEvent -> PostgreSQL transaction [Event + EventProcessing + OutboxMessage]
         -> OutboxRelay claim -> Publisher acknowledgement
         -> EventProcessor claim -> EventHandler -> HANDLED

Local tests use the in-memory publisher. When the Google Pub/Sub adapter is selected, it uses Application Default Credentials and requires EVA_PUBSUB_PROJECT_ID; this milestone does not create any GCP resources. Publication is at-least-once, so event handling remains idempotent across redelivery.

Milestone 1's Event and Outbox reliability boundary is reused by the Milestone 2 Gmail subscriber. Telegram behavior remains deferred.

Milestone 3: Goals and Situations

Milestone 3 adds scoped Goal and Situation persistence and services, lifecycle enforcement, optimistic Situation snapshots, explicit Event/Goal relationships, and deterministic Gmail-thread correlation. The local CLI can create, list, show, and update Goals and can list and inspect Situations with stable JSON output.

Gmail ingestion itself does not create Situations. The Milestone 4 relevance consumer invokes the resolver only for email that warrants operational attention. See the Goal and Situation operator guide for the mental model, command examples, lifecycle rules, and troubleshooting.

Milestone 4: Relevance engine

Milestone 4 turns stored Events into durable, revisitable relevance decisions:

Gmail -> Event + OutboxMessage -> continuous Event Relay -> eva-events
      -> relevance consumer -> screening -> bounded AI context -> application policy
      -> versioned Signal -> optional Gmail-thread Situation

The Event Relay and relevance consumer are independent long-running processes. IGNORE and RECORD decisions remain queryable and can be explicitly re-evaluated later; NOTIFY and INVESTIGATE create or reuse Situations but do not yet message the user or execute actions. Relevance is disabled by default and historical scans are always explicit. See the Relevance operator guide for GCP setup, privacy boundaries, configuration, commands, and recovery procedures.

Milestone 5: Memory and context

Milestone 5 adds two provenance-rich memory layers and a bounded context assembly path:

Explicit fact -> scoped versioned slot -> active structured context
Explicit episode -> bounded OpenAI embedding -> pgvector candidate retrieval
Situation + active Goals + facts + reranked episodes -> AgentWorkingContext

Facts preserve supersession and retraction history. Episodes are immutable summaries, support Goal and Situation links, and never expose their vectors through the service or CLI. Every operation is filtered by User and Workspace. Gmail and relevance events do not learn memory automatically in this milestone. See the Memory and Context operator guide for lifecycle, safety boundaries, configuration, examples, and smoke testing.

Milestone 6: Agent investigation

Milestone 6 launches a full agent after the relevance policy chooses NOTIFY or INVESTIGATE:

NOTIFY/INVESTIGATE Signal -> AgentRun + transactional outbox -> eva-agent-runs
                          -> scoped context + read-only Gmail tools
                          -> strict proposal-only AgentInvestigationResult

The same Cloud Run worker process now hosts a fourth agent-pull loop. Runs are leased, retried, idempotent per Signal/version, and tenant-scoped. Email remains untrusted evidence; the model cannot choose another account or gain write authority. Results may propose notifications, Situation updates, memory, follow-ups, or future actions. Milestone 7 now delivers notification proposals; the other proposal types remain inert. See the Agent investigation operator guide for setup, privacy boundaries, inspection, and recovery.

Milestone 7: Telegram conversation

Milestone 7 makes Eva both proactive and reactive over a paired private Telegram chat:

Agent notification -> Notification + outbox -> Telegram delivery -> proactive message
User message -> authenticated webhook -> Event + outbox -> conversation agent -> Notification
             -> Telegram delivery -> reply

Pairing binds immutable numeric Telegram user and chat IDs to one Eva User and Workspace. Every conversation, Situation, memory lookup, Gmail read, and response remains within that persisted scope. Replies to proactive messages recover the originating Situation; ordinary messages use the active general chat, and /new starts a fresh one. The shared Cloud Run worker now supervises six continuous loops. This milestone's Gmail tools remain read-only; Milestone 8 adds a separate, approval-gated action path. See the Telegram operator guide.

Milestone 8: Gmail actions and exact approval

Milestone 8 lets the agent propose reply or brand-new Gmail drafts without giving the model a Gmail write tool:

Agent/conversation intent -> deterministic validation -> Gmail draft creation
    -> exact Telegram card [Send | Change | Discard]
    -> immutable approval -> outbox -> Pub/Sub -> Cloud Tasks
    -> private action executor -> Gmail -> durable result + Telegram status

Draft creation is automatic, but sending always requires the paired user to approve the exact recipients, subject, body, and thread context. Change invalidates the old approval and produces a new complete draft version; Discard deletes only Eva's exact managed draft. Approvals expire after 24 hours. Ambiguous send outcomes become UNKNOWN and are never retried blindly.

Existing connectors must be reauthorized for both gmail.readonly and gmail.compose before write actions work. Reauthorization preserves the connector identity, original connection boundary, Gmail history cursor, and watch state. See the Gmail actions operator and smoke-test guide.

About

Personal Agentic AI assistant

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages